Python 2.7 mock/patch: понимание assert_called_XYZ()
Я относительно новичок в Python и модульном тестировании на Python. Из мира Java я знаю концепцию насмешливости, но она, кажется, сильно отличается от того, что я вижу на Python.
Я нашел это руководство, которое мне очень помогло: http://www.voidspace.org.uk/python/mock/index.html
Но поскольку я написал мои (несколько более сложные) тесты с издеваемыми зависимостями, я заметил, что это поведение нечистоплотного.
Я решил создать сокращенный простой пример, который также не работает, как я ожидаю.
Взгляните на это, результат и мое ожидание, которое я добавил в качестве комментариев:
import unittest
from mock import patch, Mock, MagicMock
class BasicTest(unittest.TestCase):
@patch("StringIO.StringIO")
def testSomethingNotWorkingAsExpected(self, StringIOMock):
StringIOMock.assert_called_once() # asserts, but why?
@patch("StringIO.StringIO")
def testSomethingSomehowWorking(self, StringIOMock):
# self.instantiateStringIO() # intentionally commented out
assert StringIOMock.called # does not assert (leading to failure of this test); as expected. If the above line is not commented, this asserts as expected.
def instantiateStringIO(self):
import StringIO
StringIO.StringIO()
Почему assert_called_once()
утверждает создание экземпляра StringIO
, даже если оно еще не было создано?
И почему assert ClassMock.called
приносит ожидаемые результаты?
Использование assert not ...
для утверждения метода не было вызвано Я нашел здесь: Утвердить, что функция/метод не вызывается с использованием Mock. Я перевернул этот шаблон в моем случае, опуская not
.
Где-то я нашел шаблон ClassMock.return_value
для ссылки на экземпляр. Но я понимаю это как способ создания экземпляра Mock до того, как он будет вызван, а не как способ доступа к экземпляру, который может быть создан внутренним кодом. Или я ошибаюсь?
Моя среда:
- Python 2.7.3
- mock 0.8.8
- Fedora 19
Возможно, мое понимание фальшивки/исправления неверно. Может ли кто-нибудь объяснить, что делает классный макет и как он работает?
Edit1: Добавлен вывод
... и добавил парафраз в parens для комментариев в testSomethingSomehowWorking
Это вывод:
.F
======================================================================
FAIL: testSomethingSomehowWorking (test_test.BasicTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/site-packages/mock.py", line 1224, in patched
return func(*args, **keywargs)
File "test_test.py", line 15, in testSomethingSomehowWorking
assert StringIOMock.called # does not assert; as expected
AssertionError
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
Ответы
Ответ 1
Метод assert_called_once
не существует и не выполняет утверждение. Это ничем не отличается от написания StringIOMock.assert_foo_bar_does_not_exist()
или любого другого метода. Библиотека макета не проверяет, действительно ли существует метод, вызванный макетом.
Если вы используете assert_called_once_with
, то он терпит неудачу, как ожидалось.
Вы можете использовать параметр spec
, чтобы вызвать ошибку при вызове несуществующего метода:
@patch("StringIO.StringIO", spec=StringIO.StringIO)
def testSomethingNotWorkingAsExpected(self, StringIOMock):
StringIOMock.assert_called_once() # will fail as the method doesn't exist