mock没生效主因是路径错误,须patch函数被导入调用处(如tasks.send_email)而非定义处(utils.send_email);async函数需用asyncmock或设协程return_value;私有方法内联调用不可mock,应直接替换实例属性。

Mock对象没生效,八成是路径写错了——不是函数定义的地方,而是它被导入和调用的地方。
patch目标路径必须匹配调用处的模块名
比如 utils.send_email 在 tasks.py 里被 from utils import send_email 导入,然后直接调用 send_email(),那 patch 就得写 tasks.send_email,而不是 utils.send_email。
常见错误现象:
- 测试中真实发了邮件、连了数据库
-
mock.assert_called_once()报AssertionError,但业务逻辑明明走到了那里 - mock 对象返回
None,且call_count始终为 0
验证方法:在测试函数开头加一行 print(tasks.send_email),如果输出不是 <magicmock ...></magicmock>,说明 patch 根本没打上去。
async 函数被 patch 后 await 报错
直接 @patch('module.async_func') 不行,因为 mock 返回的是普通对象,不是协程。Python 3.8+ 必须用 AsyncMock,或者手动设 return_value 为协程对象。
正确做法:
图片提示词生成器?不止如此。 马甲系统 —— 把脑海中的画面,翻译成AI能理解的专业表达。 用得越多,它越懂你:首次需要多问几句确认方向,用久了几乎一说就懂。 用得越多,它越快:缓存机制让后续对话越来越省。 RAG进化:成功案例持续入库,越跑越聪明。 输入「新手指南」查看完整功能介绍
- 用
AsyncMock:mocker.patch('module.async_func', new=AsyncMock(return_value='ok')) - 或设协程返回值:
mock_func.return_value = asyncio.Future(); mock_func.return_value.set_result('ok') - 误用
return_value=Exception()不会抛异常,只是返回一个异常实例
类属性或模块级常量 patch 后影响后续测试
patch 没 clean up,下个测试读到的就是脏数据。尤其当目标是类属性(如 Config.timeout)或模块级变量(如 utils.CONST)时,风险极高。
典型诱因:
- 手动赋值:
Config.timeout = 0.1—— 这不是 patch,不会自动还原 - 在
setup_method中用了mocker.patch.object却没调用start()/stop() - 多个测试共用同一导入路径,pytest 缓存了模块,patch 状态残留
安全做法:优先用 mocker.patch.object(Config, "timeout", new=0.1),而非直接赋值;怀疑残留时,可在测试末尾加 mocker.resetall()。
私有方法 mock 失败的真正原因
不是“私有方法不能 mock”,而是你 patch 的位置根本没被调用。如果 _helper() 只在类内部通过 self._helper() 调用,那 patch 模块路径毫无意义——Python 解析的是实例属性访问,不是模块引用。
可行方案:
- 测试中构造实例后,直接替换:
obj._helper = mocker.Mock(return_value="ok") - 若该方法是
@staticmethod,则需 patch 类路径:mocker.patch("mylib.MyClass._helper") - 断言时别漏掉
self:mock_helper.assert_called_with(mocker.ANY, "arg1"),否则一定失败
最隐蔽的坑在于:你以为在 mock 私有方法,其实该方法压根没进调用栈——先确认它是否真被外部触发,还是仅作为内联辅助存在。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










