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

Python 当测试一起运行时,所有测试中使用的外部库模拟补丁不起作用,python,unit-testing,mocking,python-unittest,Python,Unit Testing,Mocking,Python Unittest,我正在使用Python的模拟库和unittest。我正在为一个类编写单元测试,该类在其方法之一中使用外部库的函数。根据具体情况,此函数返回不同的值 假设我想测试A级: from external_library import function_foo class A(object): ... 在我的测试类中,为了使用函数从外部库返回的值,我创建了一个补丁,并且仅在定义补丁后导入类a。但是,我需要在所有测试方法中使用这个函数,并且在每个方法中它都返回不同的值 我的测试课程如下: class T

我正在使用Python的模拟库和unittest。我正在为一个类编写单元测试,该类在其方法之一中使用外部库的函数。根据具体情况,此函数返回不同的值

假设我想测试A级:

from external_library import function_foo

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

我的测试课程如下:

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
error。但是,如果我单独运行它们中的每一个,它们都会通过

我曾尝试在每种方法中使用
和patch('external_library.function_foo',side_effect=[…])
,但结果是一样的。我还尝试在
设置
方法中只创建一次补丁,启动它,在每个方法中重新分配副作用,然后在
拆卸
中停止,但没有成功

有没有关于在这种情况下什么可能起作用的想法


谢谢

需要注意的是,第二次导入模块时,会得到与第一次导入时相同的模块对象

当您第一次运行“test_1”时,
external_library.function_foo
被一个
Mock
对象替换,我们将其命名为
Mock_a
。然后您的“模块”第一次被导入,python将加载它,这意味着在“模块”内执行代码,这将把名称“function\u foo”绑定到“module”名称空间中的对象“mock\u a”,将“module”对象保存到
sys.modules
。这一次,您的测试将通过,
mock\u a的
副作用
被消耗掉

接下来是“test_2”,即
外部库。函数\u foo
替换为
Mock
对象,将其命名为
Mock\u b
。然后导入“module”,这一次不会再次加载它,而是从
sys.modules
中填充,得到与“test_1”中相同的模块对象。在此模块对象的命名空间中,名称“function\u foo”仍然绑定到对象
mock\u a
,而不是新创建的
mock\u b
。由于
mock\u a
副作用
已消耗,因此引发了
StopIteration
错误

应将修补程序应用于查找名称的位置,而不是定义名称的位置:

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

阅读有关的更多详细信息。

注意事项是,第二次导入模块时,将获得与第一次导入时相同的模块对象

当您第一次运行“test_1”时,
external_library.function_foo
被一个
Mock
对象替换,我们将其命名为
Mock_a
。然后您的“模块”第一次被导入,python将加载它,这意味着在“模块”内执行代码,这将把名称“function\u foo”绑定到“module”名称空间中的对象“mock\u a”,将“module”对象保存到
sys.modules
。这一次,您的测试将通过,
mock\u a的
副作用
被消耗掉

接下来是“test_2”,即
外部库。函数\u foo
替换为
Mock
对象,将其命名为
Mock\u b
。然后导入“module”,这一次不会再次加载它,而是从
sys.modules
中填充,得到与“test_1”中相同的模块对象。在此模块对象的命名空间中,名称“function\u foo”仍然绑定到对象
mock\u a
,而不是新创建的
mock\u b
。由于
mock\u a
副作用
已消耗,因此引发了
StopIteration
错误

应将修补程序应用于查找名称的位置,而不是定义名称的位置:

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

阅读有关的更多详细信息。

感谢您的回答和@georgexsh的精彩解释,我通过将
外部库.function\u foo
替换为
包.module.function\u foo
来实现它,感谢您的回答和@georgexsh的精彩解释,通过将
外部库.function\u foo
替换为
包.module.function\u foo