You need to enable JavaScript to run this app. pytest如何mock列表内引用的其他模块函数并验证调用状态
优惠活动
大模型
产品
解决方案
定价
更多

pytest如何mock列表内引用的其他模块函数并验证调用状态

失效原因

Python 模块为单例模式,fun_list.py 首次被导入时会立即执行FUN_LIST的初始化逻辑,直接将other_module.funA、other_module.funB的内存引用存入列表。你测试时Patch的是other_module.funB这个名称的指向,只会影响Patch生效后新访问other_module.funB的取值,无法修改已经存入FUN_LIST的旧引用,因此调用时走的还是真实函数逻辑。

解决方案

方案1:不修改原有业务代码,直接替换列表中的函数引用

直接修改fun_list中已初始化的FUN_LIST,测试完成后恢复原引用避免影响其他用例:

from unittest.mock import Mock
from demo import run_demo
from fun_list import FUN_LIST

def test_demo_funs():
    # 保存原函数引用用于测试后恢复
    original_funB = FUN_LIST[1]
    mocked_funB = Mock(return_value={})
    # 替换列表中的funB
    FUN_LIST[1] = mocked_funB
    
    try:
        run_demo()
        # 验证至少被调用一次
        assert mocked_funB.call_count >= 1
    finally:
        # 恢复原引用,避免污染其他测试用例
        FUN_LIST[1] = original_funB

方案2:调整业务代码,适配通用Mock逻辑

如果希望使用常规的@patch写法,可以修改fun_list.py的实现,让函数引用在调用时才动态获取:

调整后fun_list.py示例1:函数调用时动态构造列表

import other_module

def run_funs():
    # 每次调用时才初始化列表,会读取最新的other_module属性
    FUN_LIST = [
        other_module.funA,
        other_module.funB,
    ]
    for fun in FUN_LIST:
        fun()

调整后fun_list.py示例2:用lambda延迟执行

import other_module

FUN_LIST = [
    lambda: other_module.funA(),
    lambda: other_module.funB(),
]

def run_funs():
    for fun in FUN_LIST:
        fun()

调整后你原来的测试代码即可正常生效,不需要修改测试逻辑。


内容的提问来源于stack exchange,提问作者Mr_Somebody

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.21 02:24:01