Używam Pythona mock.patch i chciałbym zmienić wartość zwracaną dla każdego połączenia. Oto zastrzeżenie: łatana funkcja nie ma żadnych danych wejściowych, więc nie mogę zmienić wartości zwracanej na podstawie danych wejściowych.
Oto mój kod w celach informacyjnych.
def get_boolean_response():
response = io.prompt('y/n').lower()
while response not in ('y', 'n', 'yes', 'no'):
io.echo('Not a valid input. Try again'])
response = io.prompt('y/n').lower()
return response in ('y', 'yes')
Mój kod testowy:
@mock.patch('io')
def test_get_boolean_response(self, mock_io):
#setup
mock_io.prompt.return_value = ['x','y']
result = operations.get_boolean_response()
#test
self.assertTrue(result)
self.assertEqual(mock_io.prompt.call_count, 2)
io.prompt
jest po prostu niezależną od platformy (python 2 i 3) wersją "input". Ostatecznie więc staram się wyśmiewać dane wejściowe użytkowników. Próbowałem użyć listy dla wartości zwracanej, ale wydaje się, że to nie działa.
Możesz zobaczyć, że jeśli wartość zwracana jest czymś nieprawidłowym, po prostu otrzymam tutaj nieskończoną pętlę. Potrzebuję więc sposobu, aby ostatecznie zmienić wartość zwracaną, aby mój test faktycznie się zakończył.
(innym możliwym sposobem odpowiedzi na to pytanie może być wyjaśnienie, w jaki sposób mogę naśladować dane wejściowe użytkownika w teście jednostkowym)
Nie jest dupkiem w tym pytaniu, głównie dlatego, że nie mam możliwości zmiany danych wejściowych.
Jeden z komentarzy w odpowiedzi na to pytanie jest podobny, ale nie podano odpowiedzi / komentarza.
źródło
response is not 'y' or 'n' or 'yes' or 'no'
w nie robić to, co myślisz, że to robi. Zobacz Jak przetestować jedną zmienną pod kątem wielu wartości? i należy nie używaćis
do porównania wartości ciągów, korzystanie==
porównać wartości , a nie tożsamości obiektów.is
do porównania literałów ciągów. Nie rób tego. Fakt, że to działa (czasami) jest tylko szczegółem implementacji w CPythonie. Poza tymresponse is not 'y' or 'n' or 'yes' or 'no'
prawdopodobnie nie robi tego, co myślisz, że jest ...Odpowiedzi:
Możesz przypisać iterowalne do
side_effect
, a makieta zwróci następną wartość w sekwencji za każdym razem, gdy zostanie wywołana:Cytując
Mock()
dokumentację :Tak na marginesie, test
response is not 'y' or 'n' or 'yes' or 'no'
będzie nie działa; pytasz, czy wyrażenie(response is not 'y')
jest prawdziwe, czy'y'
prawdziwe (zawsze tak jest, niepusty łańcuch jest zawsze prawdziwy) itd. Różne wyrażenia po obu stronachor
operatorów są niezależne . Zobacz Jak przetestować jedną zmienną pod kątem wielu wartości?Nie należy również używać
is
do testowania na łańcuchu. Interpreter CPythona może w pewnych okolicznościach ponownie używać obiektów łańcuchowych , ale nie jest to zachowanie, na które należy liczyć.W związku z tym użyj:
zamiast; użyje to testów równości (
==
) do określenia, czyresponse
odwołuje się do łańcucha o tej samej zawartości (wartości).To samo dotyczy
response == 'y' or 'yes'
; użyjresponse in ('y', 'yes')
zamiast tego.źródło
mock
? Czy istnieje sposób na użycie łatki z MagicMock, tak jak robię to ze standardowym mockiem?Mock
klasy stardard .m.side_effect = iter(['foo', 'bar', 'baz'])
).lambda
(funkcję), a nieMagicMock
. Obiekt funkcji nie może mieć właściwości, więcside_effect
atrybut musi być iterowalny. Nie powinieneś jednak określać metody w ten sposób. Lepsze wykorzystaniemock.patch.object(requests.Session, 'post')
; skutkuje to obiektem patchera, który poprawnie automatycznie określa metodę i obsługuje jąside_effect
poprawnie.StopIteration
podnosi się. Możesz użyć dowolnego iteratora, więc możesz użyćitertools.chain(['Foo'], itertools.repeat('Bar'))
do wyprodukowaniaFoo
raz, a potem na zawszeBar
.