我正在使用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
错误。但是,如果我单独运行每一个,它们都会通过。
我尝试在每种方法中使用with patch('external_library.function_foo', side_effect=[...])
,但结果是一样的。我还尝试仅在setUp
方法中创建补丁一次,启动它,在每个方法中重新分配side_effect,然后在tearDown
停止,但它没有工作。
关于在这种情况下可能起作用的任何想法?
谢谢!
答案 0 :(得分:1)
需要注意的是,第二次导入模块it would not be loaded again时,您将获得与第一次导入时相同的模块对象。
当您第一次运行“test_1”时,external_library.function_foo
被Mock
对象替换,我们将其命名为mock_a
。然后你的“模块”第一次导入,python将加载它,意味着,在“module”中执行代码,它将名称“function_foo”绑定到“module”命名空间中的对象“mock_a”,保存“module”对象sys.modules
。这次您的测试将通过,side_effect
的{{1}}将被消耗。
接下来是“test_2”,mock_a
替换为external_library.function_foo
对象,将其命名为Mock
。然后导入“module”,这次它不会再次加载,但从mock_b
填充,你得到的模块对象与“test_1”相同。在此模块对象的命名空间中,名称“function_foo”仍绑定到对象sys.modules
,而不是新创建的mock_a
。由于mock_b
side_effect
已经消耗,因此引发了mock_a
错误。
您应该将补丁应用到查找名称的位置,而不是在其定义的位置:
StopIteration