如何在不Mock配置的情况下Mock链式导入的ActionHelpers.perform_action方法
问题
我有一个供开发者按需修改的常量配置文件,为提升可读性拆分结构如下:
from app.configuration.foo.main import FOO_RULES MAIN_RULES = { 'foo': FOO_RULES }
FOO_RULES的定义如下:
from app.helpers.foo.action_helpers import ActionHelpers FOO_RULES = { 'bar': { 'action_func': ActionHelpers.perform_action, }, }
另有RuleRunner类导入MAIN_RULES,调用时动态解析配置,若action_func不为None则传入固定参数调用:
from app.configuration.main import MAIN_RULES class RuleRunner: def __init__(self, rule_book): self.__rule_book = MAIN_RULES def run_rule(self, rule, val_1, val_2): rule = self.__rule_book[rule] action_func = rule['action_func'] if action_func is not None: action_func(val_1, val_2)
由于配置是应用核心部分需测试,但我不想Mock MAIN_RULES(避免重复测试常量),却需Mock ActionHelpers.perform_action(该方法已有单独单元测试)。现寻求如何在不Mock整个配置的前提下,正确Mock这个链式导入的方法,测试代码中??????处应填写什么模块路径:
from app.runners import RuleRunner import mock @mock.patch('??????.ActionHelpers.perform_action') def test_run_role_foo_bar_rule(action_helper_perform_action): val_1 = 'fizz' val_2 = 'buzz' RuleRunner('foo').run_rule('bar', val_1, val_2) action_helper_perform_action.assert_called_with(val_1, val_2)
解决方案
你需要填写的模块路径是**app.configuration.foo.main**。
原因很明确:ActionHelpers.perform_action是在app.configuration.foo.main模块中被导入,并且被赋值给FOO_RULES['bar']['action_func']的。当MAIN_RULES导入FOO_RULES后,实际引用的是该配置模块中已经绑定的函数对象。要Mock这个被配置引用的函数实例,必须针对它被绑定的模块路径进行操作,而非原函数所在的模块。
修改后的测试代码如下:
from app.runners import RuleRunner import mock @mock.patch('app.configuration.foo.main.ActionHelpers.perform_action') def test_run_role_foo_bar_rule(action_helper_perform_action): val_1 = 'fizz' val_2 = 'buzz' RuleRunner('foo').run_rule('bar', val_1, val_2) action_helper_perform_action.assert_called_with(val_1, val_2)
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

