Издевательский класс: Mock() или patch()?
Я использую mock с Python и задаюсь вопросом, какой из этих двух подходов лучше (читайте: больше pythonic).
Метод один. Просто создайте макет и используйте его. Код выглядит так:
def test_one (self):
mock = Mock()
mock.method.return_value = True
self.sut.something(mock) # This should called mock.method and checks the result.
self.assertTrue(mock.method.called)
Метод два. Используйте патч для создания макета. Код выглядит так:
@patch("MyClass")
def test_two (self, mock):
instance = mock.return_value
instance.method.return_value = True
self.sut.something(instance) # This should called mock.method and checks the result.
self.assertTrue(instance.method.called)
Оба метода делают то же самое. Я не уверен в различиях.
Может ли кто-нибудь просветить меня?
Ответы
Ответ 1
mock.patch
- очень сильно отличается от mock.Mock
. patch
заменяет класс макетным объектом и позволяет работать с экземпляром mock. Взгляните на этот фрагмент:
>>> class MyClass(object):
... def __init__(self):
... print 'Created [email protected]{0}'.format(id(self))
...
>>> def create_instance():
... return MyClass()
...
>>> x = create_instance()
Created [email protected]
>>>
>>> @mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
... MyClass.return_value = 'foo'
... return create_instance()
...
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
... print MyClass
... return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created [email protected]
<__main__.MyClass object at 0x100505d90>
patch
заменяет MyClass
таким образом, чтобы вы могли контролировать использование класса в вызываемых вами функциях. После исправления класса ссылки на класс полностью заменяются экземпляром mock.
mock.patch
обычно используется, когда вы тестируете что-то, что создает новый экземпляр класса внутри теста. mock.Mock
экземпляры более ясны и являются предпочтительными. Если ваш метод self.sut.something
создал экземпляр MyClass
вместо того, чтобы получать экземпляр в качестве параметра, тогда mock.patch
будет уместным.
Ответ 2
У меня есть видео YouTube.
Короткий ответ: используйте mock
, когда вы передаете вещь, которую хотите насмехаться, и patch
, если вы этого не сделали. Из двух, макет настоятельно рекомендуется, потому что это означает, что вы пишете код с надлежащей инъекцией зависимости.
Глупый пример:
# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
sentence.replace('cks','x') # We're cool and hip.
twitter_api.send(sentence)
# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
twitter_api = Twitter(user="XXX", password="YYY")
sentence.replace('cks','x')
twitter_api.send(sentence)