当一起测试 运行 时,所有测试中使用的外部库模拟补丁不起作用

External library mock patch used in all tests doesnt work when tests run together

我正在使用 Python 的模拟库和单元测试。我正在为 class 编写单元测试,它在其中一种方法中使用了外部库的函数。根据不同的情况,此函数 returns 不同的值。

假设我想测试 class A:

from external_library import function_foo

class A(object):
...

在我的测试class中,为了使用函数从外部库返回的值,我创建了一个补丁,并且只在定义补丁后导入class A。但是,我需要在我所有的测试方法中使用这个函数,并且在每个方法中它 returns 不同的值。

我的测试class如下:

class TestA(TestCase):

    @patch('external_library.function_foo', side_effect=[1, 2, 3])    
    def test_1(self, *patches):

       from module import class A
       obj = A()
       ...

    @patch('external_library.function_foo', side_effect=[1, 1, 2, 2, 3, 3])    
    def test_2(self, *patches):

       from module import class A
       obj = A()
       ...

    ...

我有 10 个测试,当我 运行 所有测试一起时只有 1 个(第一个)通过,其余的,我得到 StopIteration 错误。但是,如果我运行他们每个人都单独通过,他们都会通过

我试过在每个方法中使用 with patch('external_library.function_foo', side_effect=[...]),但结果是一样的。我还尝试在 setUp 方法中只创建一次补丁,启动它,在每个方法中重新分配 side_effect,并在 tearDown 中停止,但它没有用。

对于在这种情况下可行的方法有什么想法吗?

谢谢!

需要注意的是,第二次导入模块时,it would not be loaded again,您将获得与第一次导入时相同的模块对象。

当你第一次运行 "test_1", external_library.function_foo 替换为一个Mock 对象时,我们将其命名为mock_a。然后你的 "module" 第一次被导入,python 将加载它,意思是,在 "module" 中执行代码,它将名称 "function_foo" 绑定到对象 "mock_a"在 "module" 的命名空间中,将 "module" 对象保存到 sys.modules。这次您的测试将通过,mock_a 中的 side_effect 被消耗。

接下来是"test_2",external_library.function_foo被一个Mock对象代替,命名为mock_b。然后导入"module",这次不会再加载,而是从sys.modules填充,得到和"test_1"一样的模块对象。在这个模块对象的命名空间中,名称"function_foo"仍然绑定到对象mock_a,而不是新创建的mock_b。因为 mock_aside_effect 已经消耗,所以引发了 StopIteration 错误。

您应该将补丁应用于查找 name 的位置,而不是定义它的位置:

@patch('module.function_foo', side_effect=[1, 2, 3])    
def test_1(self, patch):
    ...

阅读有关 "Where to patch" section of the manual of patch 的更多详细信息。