python 模拟库 - 在单元测试时修补类

Ser*_*rge 6 python patch mocking

我无法理解模拟补丁是如何工作的以及它是否能够解决我的问题。

我有3个文件:与外部接口的通信(a.py)、业务逻辑(b.py)和测试(test.py)。我想修补运行测试时业务逻辑使用的外部接口。

a.py:

class SomeProductionClassINeedPatch(object):
    name = 'Production Class (communication with some external service)'
    def do_something(self):
        print '<some feature with external service>'
Run Code Online (Sandbox Code Playgroud)

b.py:

import mock
from src.tmp.mocks.a import SomeProductionClassINeedPatch

class WorkingClass(object):
    def some_method_that_uses_external_class(self, *args):
        external = self._external
        external.do_something()

    @property
    def _external(self):
        if not hasattr(self, '_ext_obj' or not self._ext_obj):
            self._ext_obj = SomeProductionClassINeedPatch()
            print isinstance(self._ext_obj, mock.MagicMock) # False
        return self._ext_obj

b = WorkingClass()
b.some_method_that_uses_external_class()
Run Code Online (Sandbox Code Playgroud)

测试.py:

import mock
from src.tmp.mocks.b import WorkingClass    # class I want to test

@mock.patch('src.tmp.mocks.a.SomeProductionClassINeedPatch')
def test_some_method_of_working_class(external_mock=None, *args):
    o = WorkingClass()
    o.some_method_that_uses_external_class()        # external interface wasn't patched: <some feature with external service> - but I need mock here!
    print '<test> - '+str(isinstance(o._external, mock.MagicMock))  # False

test_some_method_of_working_class()
Run Code Online (Sandbox Code Playgroud)

我希望在test.py中调用 o.some_method_that_uses_external_class()实际上不会使用外部接口,而是模拟对象。但似乎仍然使用实际对象。

另外,当我在 test.py 或 b.py 中检查外部接口对象的实例时 - 我无法使它们通过isinstance(object, MagicMock)检查,它总是返回 false。即使我尝试在b.py中应用相同的补丁(作为类装饰器)。我究竟做错了什么?

如果重要的话,我使用 python 2.7 和 Michael Foord 的模拟库 1.0。

Nic*_*tot 2

如修补位置中所述:

补丁的工作原理是(暂时)将一个名称指向的对象更改为另一个名称所指向的对象。可以有许多名称指向任何单个对象,因此为了使修补起作用,您必须确保修补被测试系统使用的名称。

在您的示例中,使用要修补的对象的代码位于 module 中b。当您调用 patch 时,该类已经导入到 module 中b,因此修补a不会对 产生任何影响b。您需要在以下位置路径对象b

@mock.patch('src.tmp.mocks.b.SomeProductionClassINeedPatch')
Run Code Online (Sandbox Code Playgroud)

这将为您提供预期的结果,第一个调用b未修补,而第二个调用test使用了模拟对象:

# python test.py
False
<some feature with external service>
True
<test> - True
Run Code Online (Sandbox Code Playgroud)