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

Python中如何mock闭包(内层函数)的指定返回值?

闭包内层函数可以mock,你之前的写法失效是因为目标对象不存在

你尝试的@mock.patch('outer.inner')和@mock.patch.object(outer, 'inner')无法生效的核心原因:
inner是outer运行时动态创建的局部函数,既不是模块顶层可直接导入的对象,也不是outer函数的属性,mock的patch机制找不到对应的绑定目标,自然无法替换。

以下是三种可行的实现方案,按改动成本从低到高排序:

方案1:mock内层函数依赖的外部对象(无需修改原函数)

如果你的内层函数调用了可导入的外部依赖(比如示例里的np.mean),直接mock这个依赖即可间接控制inner的返回值,是成本最低的方案:

from unittest import mock
import numpy as np

def test_outer():
    # 测试inner返回非1的分支
    with mock.patch.object(np, 'mean', return_value=2):
        res = outer([1,2,3])
        assert res == 2
    # 测试inner返回1的分支
    with mock.patch.object(np, 'mean', return_value=1):
        res = outer([1,2,3])
        assert res is None

方案2:原函数加注入入口(改动极小,可测试性最高)

如果允许对原函数做极小的兼容修改,给内层函数加默认参数作为注入入口,测试时直接传入mock对象即可,不需要依赖patch机制:

修改后的原函数

def outer(values, inner=None):
    a = 1
    # 没有传入自定义inner时使用原逻辑
    if inner is None:
        def inner():
            return np.mean(values)

    if inner() == 1:
        return None
    return inner()

测试代码

from unittest import mock

def test_outer():
    mock_inner = mock.Mock(return_value=2)
    res = outer([1,2,3], inner=mock_inner)
    assert res == 2
    # 可直接验证inner的调用情况
    mock_inner.assert_called_once()

方案3:运行时替换局部函数(无外部依赖、不能改原代码时使用)

如果inner没有可导入的外部依赖,且你不能修改原函数代码,可以通过sys.settrace在函数运行时拦截替换局部的inner对象:

from unittest import mock
import sys
# 假设outer定义在your_module模块中
from your_module import outer as original_outer

def test_outer():
    def wrapped_outer(values):
        # 跟踪函数执行,替换inner定义
        def trace_calls(frame, event, arg):
            if event == 'line' and 'inner' in frame.f_locals:
                frame.f_locals['inner'] = mock.Mock(return_value=2)
                sys.settrace(None)
            return trace_calls
        sys.settrace(trace_calls)
        try:
            return original_outer(values)
        finally:
            sys.settrace(None)
    
    with mock.patch('your_module.outer', side_effect=wrapped_outer):
        res = outer([1,2,3])
        assert res == 2

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 09:39:03