如何Mock从函数或方法内部导入的函数?
如何Mock函数内部的运行时导入及更优实现方案
一、可以Mock运行时导入的函数吗?
可以,但你需要patch导入的源模块中的目标函数,而非当前模块。
你原测试代码报错的原因是:@patch("path.to.my.module.the_thing")试图patch当前模块的the_thing,但该函数仅在方法内部导入,当前模块根本不存在这个属性。而实际代码中调用的是somewhere.the_thing,所以正确的patch目标是源模块的路径。
修改后的测试代码示例:
from unittest import TestCase from unittest.mock import patch from path.to.my.module import MyClass class MyTestCase(TestCase): @patch("somewhere.the_thing") # 此处patch源模块的the_thing def test_stuff(self, mock_the_thing): # 设置mock的返回值 mock_the_thing.return_value = 10 obj = MyClass() result = obj.my_method() # 验证计算结果 self.assertEqual(result, 14) # 验证函数被调用一次 mock_the_thing.assert_called_once()
二、更优的实现方式
函数内部导入虽能临时解决循环导入,但会降低代码可读性和测试便利性,推荐以下两种更优雅的方案:
1. 模块级延迟导入(而非函数内)
如果循环导入源于模块间互相引用,可在模块顶部导入整个源模块,而非单个函数,既能避免循环导入,又能让代码结构更清晰:
# 模块顶部导入整个源模块 import somewhere class MyClass: def my_method(self): x = somewhere.the_thing() return x + 4
测试时同样patchsomewhere.the_thing即可,逻辑与之前一致。
2. 依赖注入(推荐)
通过将依赖函数作为参数传入类或方法,彻底解耦依赖关系,不仅避免循环导入,测试时无需使用patch,直接传入mock对象即可:
class MyClass: def __init__(self, the_thing=None): # 保留默认导入逻辑,兼容原有调用方式 if the_thing is None: from somewhere import the_thing self.the_thing = the_thing def my_method(self): x = self.the_thing() return x + 4
对应的测试代码(无需patch):
from unittest import TestCase from unittest.mock import Mock from path.to.my.module import MyClass class MyTestCase(TestCase): def test_stuff(self): # 创建mock对象并设置返回值 mock_thing = Mock(return_value=10) # 初始化类时传入mock obj = MyClass(the_thing=mock_thing) result = obj.my_method() self.assertEqual(result, 14) mock_thing.assert_called_once()
这种方式符合依赖倒置原则,代码的可测试性和扩展性更强。
内容的提问来源于stack exchange,提问作者Daniel Quinn
相关产品推荐
相关产品推荐

