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
相关产品推荐
相关产品推荐

