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

pytest测试中如何正确mock多层嵌套调用链内的c函数

mock不生效的核心原因

mocker.patch(底层是标准库的unittest.mock.patch)的核心替换规则是:必须替换被测试代码实际查找目标时所在命名空间下的名称。你原来patchc的路径本身是符合规则的,不生效本质是两个低级问题:

  • 期望值计算错误:你定义的mocked_c返回全1数组,经过b()加2、a()加1后,最终输出是全4数组,断言写==5必然失败,很容易误判为mock没生效。你之前patchb能正常生效,是因为mockb时返回值刚好满足加1等于5的断言逻辑,和patch方式本身无关。
  • 少数场景下如果模块加载顺序特殊,直接patch模块属性可能出现引用不同步,用更精准的patch方式可以彻底规避这个问题。
正确实现代码

基础写法(和你patchb的逻辑完全一致):

import numpy as np
from src.sample import a

def mocked_c():
    # 如果要让a()返回全5满足原断言,这里改成返回全2即可
    # return np.repeat(2, repeats=10)
    return np.repeat(1, repeats=10)

def test_a(mocker):
    mocker.patch('src.sample.c', mocked_c)
    res = a()
    # 对应返回全1的mock,期望值为4;返回全2则期望值为5
    assert np.all(res == 4)

如果需要更精准地只修改b内部调用的c,不影响模块其他位置对c的调用,可以直接替换b函数全局作用域的引用:

def test_a(mocker):
    from src.sample import b
    mocker.patch.object(b.__globals__, 'c', mocked_c)
    assert np.all(a() == 4)
避坑要点
  • 不要patch测试文件本地导入的c:比如你在测试文件写from src.sample import c后去patch当前文件命名空间的c是完全无效的,b函数执行时只会在自己所属的src.sample模块全局空间查找c,不会访问测试文件的命名空间。
  • patch时传入mock函数不要加括号:如果写成mocker.patch('src.sample.c', mocked_c()),会把c替换成mocked_c的执行结果(numpy数组),后续调用c()会直接抛出numpy.ndarray is not callable的类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:30:53