代码之家  ›  专栏  ›  技术社区  ›  Larissa Leite

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

  •  3
  • Larissa Leite  · 技术社区  · 7 年前

    我正在使用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 方法,启动它,在每个方法中重新分配副作用,并在 tearDown ,但它不起作用。

    关于这种情况下什么可能有效,有什么想法吗?

    谢谢

    1 回复  |  直到 7 年前
        1
  •  6
  •   georgexsh    7 年前

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

    第一次运行“test\u 1”时, external_library.function_foo 替换为 Mock 对象,我们来命名它 mock_a . 然后您的“模块”第一次被导入,python将加载它,意味着在“模块”内执行代码,这将把名称“function\u foo”绑定到“module”命名空间中的对象“mock\u a”,将“module”对象保存到 sys.modules . 这次你的考试会通过,而且 side_effect 属于 模拟\u a 消费。

    接下来是“test\u 2”, external\u库。函数\u foo 替换为 嘲弄 对象,将其命名为 mock_b . 然后导入“模块”,这次不会再次加载,而是从 系统。模块 ,则得到与“test\u 1”中相同的模块对象。在此模块对象的命名空间中,名称“function\u foo”仍然绑定到对象 模拟\u a ,而不是新创建的 模拟\u b . 因为 副作用 属于 模拟\u a 已消费, StopIteration 出现错误。

    您应该将修补程序应用于 名称 查找,但不在定义的位置:

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

    阅读有关 "Where to patch" section of the manual of patch .