python 中的 monkeypatch,将模拟泄露给其他测试,导致它们失败

monkeypatch in python, leaking mocks to other tests causing them to fail

我在编写 pytest 单元测试时正在修补其他函数调用,如下所示:

from _pytest.monkeypatch import MonkeyPatch
from third_party import ThirdParty

def test_my_func():
    resp1= "resp1"
    monkeypatch = MonkeyPatch()
    def mock_other_method(*args, **kwargs):
        return resp1
    monkeypatch.setattr(ThirdParty, "other_method", mock_other_method)
    assert ThirdParty().other_method() == "resp1"
    # Some assertions

def test_my_func2():
    monkeypatch = MonkeyPatch()
    expected_result = "This is expected"
    result_third_party = ThirdParty().other_method()
    assert result_third_party == expected_result

其中, third_party.py 有:

class ThirdParty:
       def other_method(self):
          return "This is expected"

这些测试 运行 独立 运行 很好(我刚写的,所以可能有一些语法错误)。但是当我 运行 它作为 pytest -v 时,第二次测试将失败。原因是在调用 other_method 时,它将 return 模拟方法:mock_other_method,并且由于响应不同,它将失败。请提出一些解决方案

我通过在每个测试结束时添加 monkeypatch.undo() 找到了解决方案。这将防止 monkeypatch() 泄漏到其他函数中

monkeypatchpytest fixture 因此 不应该是进口的。相反,您必须在测试函数中将其作为参数提供。 Pytest 在测试开始时加载所有固定装置并按名称查找它们,因此正确的用法是:

from third_party import ThirdParty
# no import from pytest internal module! 

def test_my_func(monkeypatch):
    resp1 = "resp1"
    def mock_other_method(*args, **kwargs):
        return resp1
    monkeypatch.setattr(ThirdParty, "other_method", mock_other_method)
    assert ThirdParty().other_method() == resp1

monkeypatch fixture 具有函数范围,这意味着补丁将在每个测试函数后自动恢复。

请注意,不鼓励使用内部 pytest API(例如导入 _pytest),因为它可能会随着新版本的变化而变化,并且因为有更方便和安全的使用这些功能的方法(而不是最后,因为这些都记录在案)。如果您使用 pytestpytest 插件提供的夹具,您永远不应该自己操心清理夹具 - 很容易忘记清理并产生不必要的副作用。