You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 11:27:20