Python mock:包装实例方法

Fil*_*rda 7 python-2.7 python-mock

我想要什么: 确保Foowith语句中创建的所有实例都foo通过wraps=Foo.foo. 我想要这个的原因是我可以跟踪创建的所有实例call_count的方法。现在我这么说似乎有点不可能......fooFoo

>>> from mock import patch
...
... class Foo(object):
...
...     def foo(self):
...         return "foo"
...
... with patch("__main__.Foo.foo", wraps=Foo.foo) as m:
...     foo = Foo()
...     print(foo.foo())

Traceback (most recent call last):
  File "a.py", line 12, in <module>
    print(foo.foo())
  File "/disk/software/lib/python27/mock/mock.py", line 1062, in __call__
    return _mock_self._mock_call(*args, **kwargs)
  File "/disk/software/lib/python27/mock/mock.py", line 1132, in _mock_call
    return self._mock_wraps(*args, **kwargs)
TypeError: unbound method foo() must be called with Foo instance as first argument (got nothing instead)
Run Code Online (Sandbox Code Playgroud)

问题 模拟foo方法未绑定到foo通过创建的实例,foo = Foo()因为它包装了未绑定的方法Foo.foo。有谁知道如何确保模拟方法绑定到一个实例?

我已经知道的:

>>> foo = Foo()
... with patch.object(foo, "foo", wraps=foo.foo) as m:
...     print(foo.foo())
"foo"
Run Code Online (Sandbox Code Playgroud)

但这并不能满足我的约束,即对象必须在patch上下文中实例化。

Fil*_*rda 6

我上面提出的和不正确的解决方案的问题

with patch("__main__.Foo.foo", wraps=Foo.foo) as m:
    ...
Run Code Online (Sandbox Code Playgroud)

是对foo方法进行了Foo模拟,以便它包装未绑定的方法Foo.foo,这自然不起作用,因为未绑定的方法Foo.foo不知道稍后调用时它附加到哪个实例。

我能想到的最简单的解决方案

from mock import patch, MagicMock

class Foo:

    def foo(self):
        return "foo"

class MockFoo(Foo):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # Every instance of MockFoo will now have its `foo` method 
        # wrapped in a MagicMock
        self.foo = MagicMock(wraps=self.foo)

with patch("__main__.Foo", MockFoo) as m:
    foo = Foo()
    print(foo.foo())
    assert foo.foo.call_count == 1
Run Code Online (Sandbox Code Playgroud)

  • @nitely是的,您仍然需要实例来检查`call_count`,但是您不需要实例来应用补丁。当类在被测代码深处实例化并且实例返回到测试代码时,这非常有用。当返回到测试代码时,测试可以检查该特定实例的“call_count”。如果您想跟踪补丁块中所有实例的总和“call_count”而不访问实例本身,那么这不是适合您的解决方案。 (2认同)