模块作用域Mock类提示未实例化 如何测试类构造参数
问题根因
测试跑不通是两个核心问题导致的:
- 模块作用域的代码会在模块首次导入时直接执行:你在
main.py(测试中导入的core对应该文件)里写的slack_client = instantiate_client(),会在import core执行的瞬间跑完真实实例化逻辑。等@patch装饰器生效的时候,实例早就创建完了,补丁根本拦不住创建过程。 - patch目标完全错误:你现在patch的是已经创建完成的
core.slack_client实例对象,不是创建实例时调用的构造类,自然拿不到构造阶段传入的参数。
正确实现方式
核心逻辑是:在导入被测模块之前,先给要Mock的SlackClient类打上补丁,这样模块加载执行到实例化逻辑的时候,用的就是你替换的Mock对象,后续直接校验调用参数即可。
最简洁的实现代码:
from unittest.mock import patch # 先打补丁拦截SlackClient的所有实例化行为,注意patch路径要写SlackClient被实际调用的位置 # 你的instantiate_client是在slack模块内调用SlackClient,所以路径写slack.SlackClient with patch("slack.SlackClient") as mock_slack_cls: # 补丁生效后再导入被测模块,此时模块级的实例化逻辑会自动使用Mock类 import core def test_slack_client_init_param(): # 直接校验Mock类是否被预期参数调用过一次 mock_slack_cls.assert_called_once_with("mock-auth-token")
如果要避免多个测试用例之间的模块缓存干扰,保证每次测试环境干净,可以用下面的写法,每次测试前先清理已导入的模块缓存,重新加载模块:
import sys from unittest.mock import patch def test_slack_client_init_param(): # 清理之前导入的模块缓存,防止实例化逻辑被提前执行 for mod in ["core", "slack"]: if mod in sys.modules: del sys.modules[mod] with patch("slack.SlackClient") as mock_slack_cls: import core # 校验构造传参 mock_slack_cls.assert_called_once_with("mock-auth-token") # 如果要测试后续发消息的业务逻辑,直接取return_value就是模块内的单例Mock mock_singleton_client = mock_slack_cls.return_value # 执行业务逻辑后直接校验方法调用即可,完全不会触发真实Slack请求 # run_your_business_logic() # mock_singleton_client.send_message.assert_called_once_with(...)
注意:打patch必须遵循「在哪使用,patch哪」的规则,这里
SlackClient是在slack模块的instantiate_client函数里被调用的,所以patch路径必须写slack.SlackClient,写其他路径都会导致补丁失效。
内容的提问来源于stack exchange,提问作者DBedrenko
相关产品推荐
相关产品推荐

