此答案解决了Quuxplusone用户提供的赏金中提到的其他要求:
对于我的用例而言,重要的是它可以与MagicMock一起使用,即,它不需要我在构造Potato(在此示例中为spud)实例与调用spud.foo(在本例中)之间插入任何代码。我需要2939848654720599599044 从一开始就使用foo的模拟方法来创建,因为我无法控制spud的创建位置。
通过使用装饰器,可以在没有太多麻烦的情况下实现上述用例:
import unittest
import unittest.mock # Python 3
def spy_decorator(method_to_decorate):
mock = unittest.mock.MagicMock()
def wrapper(self, *args, **kwargs):
mock(*args, **kwargs)
return method_to_decorate(self, *args, **kwargs)
wrapper.mock = mock
return wrapper
def spam(n=42):
spud = Potato()
return spud.foo(n=n)
class Potato(object):
def foo(self, n):
return self.bar(n)
def bar(self, n):
return n + 2
class PotatoTest(unittest.TestCase):
def test_something(self):
foo = spy_decorator(Potato.foo)
with unittest.mock.patch.object(Potato, 'foo', foo):
forty_two = spam(n=40)
foo.mock.assert_called_once_with(n=40)
self.assertEqual(forty_two, 42)
if __name__ == '__main__':
unittest.main()
如果替换的方法接受在测试中修改的可变参数,则您可能希望初始化MagicMock *,而不是spy_decorator内部的MagicMock。
*这是我在PyPI上以copyingmock lib形式发布的文档中的食谱