Насмешка над классом: Mock () или patch ()? - PullRequest
102 голосов
/ 18 ноября 2011

Я использую mock с Python, и мне было интересно, какой из этих двух подходов лучше (читай: более питонический).

Метод один : Просто создайте фиктивный объект и используйте его. Код выглядит так:

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)

Оба метода делают одно и то же. Я не уверен в различиях.

Может ли кто-нибудь просветить меня?

Ответы [ 2 ]

139 голосов
/ 18 ноября 2011

mock.patch очень сильно отличается от mock.Mock.patch заменяет класс на фиктивный объект и позволяет вам работать с экземпляром фиктивного.Взгляните на этот фрагмент:

>>> class MyClass(object):
...   def __init__(self):
...     print 'Created MyClass@{0}'.format(id(self))
... 
>>> def create_instance():
...   return MyClass()
... 
>>> x = create_instance()
Created MyClass@4299548304
>>> 
>>> @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 MyClass@4300234128
<__main__.MyClass object at 0x100505d90>

patch заменяет MyClass таким образом, который позволяет вам контролировать использование класса в вызываемых вами функциях.Когда вы исправляете класс, ссылки на класс полностью заменяются экземпляром макета.

mock.patch обычно используется при тестировании чего-либо, что создает новый экземпляр класса внутри теста.mock.Mock экземпляры более понятны и предпочтительны.Если ваш метод self.sut.something создал экземпляр MyClass вместо получения экземпляра в качестве параметра, тогда здесь уместно было бы mock.patch.

18 голосов
/ 21 октября 2017

У меня есть видео YouTube по этому вопросу.

Краткий ответ: используйте mock, когда вы передаете то, что хотите высмеять, и patch, есливы не.Из них настоятельно рекомендуется использовать mock, поскольку это означает, что вы пишете код с надлежащим внедрением зависимостей.

Глупый пример:

# 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...