模拟类:Mock()或patch()?


116

我在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)

两种方法都做同样的事情。我不确定这些差异。

谁能启发我?


10
作为一个从未尝试过Mock()或补丁程序的人,即使我不了解实际的差异,我也认为第一个版本更加清晰,并显示了您想做什么。我不知道这是否有帮助,但我认为传达初学者的感觉可能很有用。
Michael Brennan

2
@MichaelBrennan:谢谢您的评论。确实是有用的。
Sardathrion-反对SE滥用

Answers:


151

mock.patch与...是一个非常不同的生物mock.Mockpatch 模拟对象替换该类,并允许您使用模拟实例。看一下这个片段:

>>> 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>

patchMyClass以允许您控制所调用函数中类的用法的方式进行替换。修补类后,对该类的引用将完全由模拟实例替换。

mock.patch通常在测试要在测试内部创建类的新实例的东西时使用。 mock.Mock实例更清晰,更可取。如果您的self.sut.something方法创建了的实例MyClass而不是将实例作为参数接收,则mock.patch此处适当。


2
@ D.Shawley我们如何修补到在另一个需要测试的类中实例化的类。
ravi404

4
@ravz- 阅读“修补程序”。这是要正常工作的更困难的事情之一。
D.Shawley

我的模拟测试类似于方法二。我希望MyClass实例引发异常。我已经试过了mock.side_effect和mock.return_value.side_effect,但都没有用。我该怎么办?
侯赛因

5
@ D.Shawley链接已断开,现在可以在这里找到:“修补位置”
RazerM 2015年


27

我有一个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)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.