pytest fixture中mock.patch在其他测试运行后失效的解决方法
问题:Mock函数批量测试失效的修复方案
问题代码与现象
被测试模块(some_module.py)
from other.module import a_func # 默认返回False def do_stuff(): return "banana" if a_func() else "pear"
测试模块
import pytest from unittest import mock from some_module import do_stuff @pytest.fixture def my_fixture(): with mock.patch("other.module.a_func", lambda: True): yield class TestMyStuff: def test_something(self): assert do_stuff() == "pear" def test_something_else(self, my_fixture): assert do_stuff() == "banana"
现象:单独运行test_something_else时测试通过,但批量运行全部测试时该测试失败。
问题原因
被测试模块中使用from other.module import a_func的方式导入函数,会在some_module模块内创建一个a_func的本地引用。批量测试时,test_something先执行,此时some_module被导入,本地引用绑定了原始的a_func(返回False)。后续my_fixture中patch的是other.module.a_func,但不会影响已经绑定到some_module里的本地引用,所以do_stuff调用的还是原始函数,导致断言失败。
修复方案
方案1:修改Mock的目标路径
直接patch被测试模块内的本地引用,而不是原始模块的函数:
@pytest.fixture def my_fixture(): # 目标路径改为被测试模块中的a_func引用 with mock.patch("some_module.a_func", lambda: True): yield
这是最直接的修复方式,无需修改原业务代码,只调整测试中的patch路径即可。
方案2:重构业务代码,通过模块访问函数
修改被测试模块的导入方式,让函数调用始终指向原始模块的属性,这样patch原始模块就能生效:
# some_module.py import other.module def do_stuff(): # 直接通过模块访问a_func return "banana" if other.module.a_func() else "pear"
这种方式从根源上避免了本地引用导致的mock问题,后续测试无需调整patch路径,更符合可测试性的代码设计。
方案3:测试中重新加载被测试模块
如果无法修改业务代码,可以在fixture中重新加载被测试模块,确保每次测试都使用patch后的函数引用:
import importlib import some_module @pytest.fixture def my_fixture(): with mock.patch("other.module.a_func", lambda: True): # 重新加载模块,刷新本地引用 importlib.reload(some_module) yield
注意:模块重载可能会重置模块级别的变量,使用时需评估是否有副作用。
内容的提问来源于stack exchange,提问作者theberzi
相关产品推荐
相关产品推荐

