如何使用mock.patch将函数替换为带自定义参数的自身且不触发递归
解决方案
问题根因
你之前的写法触发递归的核心原因是:patch生效后,mymodule.myfunction已经被替换为你写的lambda函数,lambda内部再调用mymodule.myfunction实际是调用自身,自然会触发栈溢出。
方案1:提前保存原始函数引用(最通用)
在patch还未生效的模块导入阶段,先把原始函数的引用存到独立变量中,patch后的回调直接调用这个原始引用即可规避递归,搭配functools.partial可以更简洁地绑定参数:
import unittest from unittest.mock import patch from functools import partial import mymodule import production # 模块加载时就保存未被patch的原始函数引用 original_myfunction = mymodule.myfunction class MyTest(unittest.TestCase): @patch('production.mymodule.myfunction', new=partial(original_myfunction, devmode=True)) def test_main_with_mymodule_function_does_not_raise_exception(self): # 这是一个集成测试,myfunction在main内部被调用 try: production.main() except Exception as e: self.fail(e)
方案2:直接修改函数默认参数(更轻量,无需mock)
如果你的需求只是修改devmode的默认值,完全不需要用mock替换函数,直接修改函数的默认参数元组即可:
import unittest import mymodule import production class MyTest(unittest.TestCase): def test_main_with_mymodule_function_does_not_raise_exception(self): # 保存原有默认参数 origin_defaults = mymodule.myfunction.__defaults__ # 假设devmode是函数最后一个位置参数,默认值为False,替换为True new_defaults = list(origin_defaults) new_defaults[-1] = True mymodule.myfunction.__defaults__ = tuple(new_defaults) try: production.main() except Exception as e: self.fail(e) finally: # 测试结束后恢复原有默认参数,避免影响其他用例 mymodule.myfunction.__defaults__ = origin_defaults
注意:如果
devmode是关键字-only参数(即定义在*之后),需要修改的是mymodule.myfunction.__kwdefaults__字典而非__defaults__。
内容的提问来源于stack exchange,提问作者Florian Fasmeyer
相关产品推荐
相关产品推荐

