Używam biblioteki Mock do testowania mojej aplikacji, ale chcę zapewnić, że jakaś funkcja nie została wywołana. Mock doktorzy mówią o metodach takich jak mock.assert_called_with
i mock.assert_called_once_with
, ale nie znalazłem niczego podobnego mock.assert_not_called
lub związanego z weryfikacją, że mock NIE został wywołany .
Mógłbym użyć czegoś takiego jak poniżej, chociaż nie wydaje się to fajne ani pytoniczne:
def test_something:
# some actions
with patch('something') as my_var:
try:
# args are not important. func should never be called in this test
my_var.assert_called_with(some, args)
except AssertionError:
pass # this error being raised means it's ok
# other stuff
Jakieś pomysły, jak to osiągnąć?
python
unit-testing
mocking
python-mock
Gerard
źródło
źródło
Odpowiedzi:
To powinno działać w Twoim przypadku;
assert not my_var.called, 'method should not have been called'
Próba;
>>> mock=Mock() >>> mock.a() <Mock name='mock.a()' id='4349129872'> >>> assert not mock.b.called, 'b was called and should not have been' >>> assert not mock.a.called, 'a was called and should not have been' Traceback (most recent call last): File "<stdin>", line 1, in <module> AssertionError: a was called and should not have been
źródło
AttributeError: MockCallable instance has no attribute 'called'
sudo easy_install -U mock
ifrom mock import Mock
na MacOS, powyższe działa bez problemu. Nigdy nie instalowałem Django :)from mock import Mock
Python Mock 0.1.0 do moich testów. Czy coś z tego brzmi problematycznie?module_to_test.another_module.class = mock.Mock()
, czy możesz potwierdzić, że to nie zapamiętuje wywołań w różnych przypadkach testowych (instancje unittest.TestCase)? Myślę, że licznik połączeń nie resetuje się w tym przypadkuChociaż stare pytanie, chciałbym dodać, że obecnie
mock
biblioteka (backport unittest.mock) obsługujeassert_not_called
metodę.Po prostu zaktualizuj swój;
pip install mock --upgrade
źródło
Możesz sprawdzić
called
atrybut, ale jeśli Twoja asercja się nie powiedzie, następną rzeczą, którą będziesz chciał wiedzieć, jest coś o nieoczekiwanym wywołaniu, więc równie dobrze możesz zorganizować wyświetlanie tych informacji od samego początku. Używającunittest
, możesz sprawdzić zawartośćcall_args_list
zamiast:Gdy to się nie powiedzie, wyświetla następujący komunikat:
źródło
Podczas testowania przy użyciu klasy dziedziczy unittest.TestCase możesz po prostu użyć metod takich jak:
i podobne (w dokumentacji Pythona znajdziesz resztę).
W naszym przykładzie możemy po prostu stwierdzić, czy właściwość mock_method.called ma wartość False , co oznacza, że ta metoda nie została wywołana.
import unittest from unittest import mock import my_module class A(unittest.TestCase): def setUp(self): self.message = "Method should not be called. Called {times} times!" @mock.patch("my_module.method_to_mock") def test(self, mock_method): my_module.method_to_mock() self.assertFalse(mock_method.called, self.message.format(times=mock_method.call_count))
źródło
Ze
python >= 3.5
można użyćmock_object.assert_not_called()
.źródło
Sądząc po innych odpowiedziach, nikt oprócz @ rob-kennedy nie mówił o
call_args_list
.To potężne narzędzie, dzięki któremu możesz wdrożyć dokładnie odwrotnie niż
MagicMock.assert_called_with()
call_args_list
to listacall
obiektów. Każdycall
obiekt reprezentuje wywołanie wykonane na fałszywym wywołaniu.>>> from unittest.mock import MagicMock >>> m = MagicMock() >>> m.call_args_list [] >>> m(42) <MagicMock name='mock()' id='139675158423872'> >>> m.call_args_list [call(42)] >>> m(42, 30) <MagicMock name='mock()' id='139675158423872'> >>> m.call_args_list [call(42), call(42, 30)]
Korzystanie z
call
obiektu jest łatwe, ponieważ można go porównać z krotką o długości 2, w której pierwszy składnik jest krotką zawierającą wszystkie argumenty pozycyjne powiązanego wywołania, podczas gdy drugi składnik jest słownikiem słów kluczowych arguments.>>> ((42,),) in m.call_args_list True >>> m(42, foo='bar') <MagicMock name='mock()' id='139675158423872'> >>> ((42,), {'foo': 'bar'}) in m.call_args_list True >>> m(foo='bar') <MagicMock name='mock()' id='139675158423872'> >>> ((), {'foo': 'bar'}) in m.call_args_list True
Tak więc sposobem rozwiązania konkretnego problemu PO jest
def test_something(): with patch('something') as my_var: assert ((some, args),) not in my_var.call_args_list
Zauważ, że w ten sposób, zamiast po prostu sprawdzać, czy wywołano fałszywe wywołanie,
MagicMock.called
możesz teraz sprawdzić, czy zostało wywołane z określonym zestawem argumentów.To przydatne. Powiedzmy, że chcesz przetestować funkcję, która pobiera listę i wywołuje inną funkcję
compute()
, dla każdej wartości listy tylko wtedy, gdy spełniają określony warunek.Możesz teraz kpić
compute
i sprawdzić, czy została wywołana na jakiejś wartości, ale nie na innych.źródło