如何在多模块中mock全局依赖的get_args函数?
解决方案
方法1:Patch get_args的原始定义模块
所有模块的get_args都是从同一个源模块导入的,直接patch这个原始定义位置,就能让所有导入该函数的模块都使用mock版本。
假设get_args定义在第三方库的thirdparty.config模块中,测试代码如下:
from unittest.mock import patch from thirdparty.mod1 import f1 def test_single_call_mock(): # 补丁原始定义位置的get_args with patch("thirdparty.config.get_args", return_value="mocked_param"): f1() # 此时f1和它调用的f2中的get_args都会被mock
原理:Python的import机制是,模块导入的是对原始对象的引用,补丁原始模块中的函数后,所有导入该函数的地方都会指向mock对象。
方法2:直接Patch全局对象_ARGS
既然get_args是_ARGS的getter,直接mock这个全局对象的属性或本身,也能达到修改所有调用结果的目的:
替换整个_ARGS对象
from unittest.mock import patch from thirdparty.mod1 import f1 def test_single_call_args(): with patch("thirdparty.config._ARGS", {"key": "mocked_value"}): f1()
仅修改特定属性(更安全,避免替换整个对象)
import thirdparty.config from unittest.mock import patch from thirdparty.mod1 import f1 def test_single_call_args_attr(): with patch.object(thirdparty.config._ARGS, "key", "mocked_value"): f1()
替代方案:自定义上下文管理器临时修改
如果不想使用mock库,可以自己实现上下文管理器,临时修改_ARGS并自动恢复原始状态:
import thirdparty.config class TemporaryArgs: def __init__(self, temp_values): self.temp_values = temp_values self.original_values = {} def __enter__(self): # 保存原始值,覆盖需要修改的参数 for key, value in self.temp_values.items(): if key in thirdparty.config._ARGS: self.original_values[key] = thirdparty.config._ARGS[key] thirdparty.config._ARGS[key] = value def __exit__(self, exc_type, exc_val, exc_tb): # 恢复原始值,清理临时新增的键 for key in self.temp_values.keys(): if key in self.original_values: thirdparty.config._ARGS[key] = self.original_values[key] else: del thirdparty.config._ARGS[key] # 使用方式 from thirdparty.mod1 import f1 with TemporaryArgs({"key": "temporary_param"}): f1() # 单次调用期间参数被修改,退出上下文后自动恢复
内容的提问来源于stack exchange,提问作者Green 绿色
相关产品推荐
相关产品推荐

