我们最近从单元测试切换到了 pytest。我在使用 mocker.patch 作为上下文管理器时遇到了一个奇怪的问题。考虑以下示例。
模块_a.py
class MyClass:
def value(self):
return 10
模块_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 的 value method 方法将被恢复(返回值 10),但是第二个断言语句的测试失败,并出现断言错误 20 != 10
如果我使用完全相同的测试,但将 mocker.patch
替换为 unittest.mock.patch
,它就会通过。我认为 pytest-mock 与 unittest.mock 共享相同的 API,所以我很困惑为什么会有差异。
最佳答案
使用pytest-mock
,拆卸是在退出 fixture 上下文时完成的。 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 想要避免的,以使您的测试更具可读性,因此,如果您不完全使用固定装置进行设置和拆卸,那么您就有点错过了重点。
关于python - pytest-mock 补丁上下文管理器在退出时不恢复对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58294161/