You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 06:10:35