嘲笑一个类:模拟()或补丁()?

我正在使用模拟 Python,并想知道这两种方法哪一个更好(阅读:更pythonic)。

方法一 :只需创build一个模拟对象并使用它。 代码如下所示:

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) 

方法二 :使用补丁创build一个模拟。 代码如下所示:

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

两种方法都是一样的。 我不确定这种差异。

谁能开导我吗?

mock.patch是一个非常不同于mock.Mockpatch 模拟对象replace类,并让您使用模拟实例。 看看这个片段:

 >>> 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以允许您在调用的函数中控制类的用法的方式replaceMyClass 。 一旦你修补了一个类,对这个类的引用就被模拟实例完全替代了。

当你正在testing一些在testing中创build一个类的新实例时,通常使用mock.patchmock.Mock实例更清晰,更mock.Mock 。 如果你的self.sut.something方法创build了MyClass一个实例,而不是接收一个实例作为参数,那么mock.patch在这里是适当的。

我有这个YouTubevideo 。

简短的回答:当你传递你想要嘲笑的东西的时候使用mock ,如果不是,则使用patch 。 在这两者中,mock是强烈的首选,因为这意味着你正在编写具有适当dependency injection的代码。

愚蠢的例子:

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