pytest-mock 补丁上下文管理器不在退出时恢复对象

pytest-mock patch context manager not restoring object on exit

我们最近从 unittest 切换到了 pytest。使用 mocker.patch 作为上下文管理器时,我遇到了一个奇怪的问题。考虑以下示例。

module_a.py

class MyClass:
    def value(self):
        return 10

module_b.py

import module_a
class AnotherClass:
    def get_value(self):
        return module_a.MyClass().value()

test_module_b.py

from module_b import AnotherClass
def test_main_2(mocker):
    with mocker.patch('module_a.MyClass.value', return_value=20):
        value = AnotherClass().get_value()
        assert value == 20
    value = AnotherClass().get_value()
    assert value == 10

我希望一旦上下文管理器退出,MyClass 的值方法方法将被恢复(return 值为 10),但是第二个断言语句的测试失败并出现断言错误 20 != 10 如果我使用完全相同的测试,但将 mocker.patch 替换为 unittest.mock.patch,它会通过。我认为 pytest-mock 与 unittest.mock 共享相同的 API,所以我很困惑为什么会有差异。

使用 pytest-mock,在退出夹具上下文时完成拆卸。 mocker.patch 对象不仅仅是 mock.patch.

的简单别名

在编写 pytest 风格的测试时,您不应该在测试函数中需要上下文管理器,事实上 the purpose of the pytest-mock plugin is to make the use of context managers and function decorators for mocking unnecessary

如果出于某种原因你确实需要从 测试本身中进行拆卸步骤,那么你需要普通的旧模拟 API,它在 pytest 中也能正常工作。

from unittest.mock import patch

def test_main_2():
    with patch('module_a.MyClass.value', return_value=20):
        value = AnotherClass().get_value()
        assert value == 20
    value = AnotherClass().get_value()
    assert value == 10

请注意,这种嵌套结构实际上是 pytest 打算避免的,以使您的测试更具可读性,因此如果您不完全使用固定装置进行设置和拆卸,您就有点忽略了重点。