当一起测试 运行 时,所有测试中使用的外部库模拟补丁不起作用
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_a
的 side_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
的更多详细信息。
我正在使用 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_a
的 side_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
的更多详细信息。