Издевательский класс: 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)