pytest-mock 的 patch 没生效最常见原因是路径写错:须patch函数被导入使用处的路径(如tasks.send_email),而非定义处(utils.send_email);async函数需用AsyncMock或设协程return_value,否则await报错。

pytest-mock 的 patch 为什么没生效?
最常见原因是 patch 目标路径写错了——不是函数定义处的路径,而是它被**导入和使用处**的路径。比如你在 utils.py 里定义了 send_email(),但在 tasks.py 中 from utils import send_email,然后调用它;这时必须 patch tasks.send_email,而不是 utils.send_email。
其他典型表现包括:
- 测试中函数仍真实执行(比如发了真实邮件、连了真实数据库)
-
mock.assert_called_once()报AssertionError,但代码逻辑明明走到了那里 - mock 对象返回
None或默认值,但没触发任何调用记录
patch 的三种写法怎么选?
核心原则:越靠近调用点,越不容易出错。优先用装饰器或上下文管理器,避免模块级 patch 干扰其他测试。
- 装饰器方式(推荐):
@patch('tasks.send_email')<br>def test_process_order(mock_send):<br> process_order()<br> mock_send.assert_called_once() - 上下文管理器(适合单次/条件 patch):
def test_with_side_effect():<br> with patch('tasks.send_email') as mock_send:<br> mock_send.return_value = 'ok'<br> result = process_order()<br> assert result == 'ok' - 手动 start/stop(极少需要):容易漏掉 stop,导致 mock 泄漏到后续测试,不建议
mock 对象返回值和副作用设置不对
return_value 是静态返回,side_effect 才能模拟异常、动态值或真实函数行为。很多人卡在“mock 返回了,但业务逻辑没按预期分支走”,其实是该用 side_effect 没用。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
- 想让函数抛异常:
mock_fetch.side_effect = requests.ConnectionError - 想每次调用返回不同值:
mock_read.side_effect = ['line1', 'line2', StopIteration] - 想转发调用到真实函数(只 mock 部分行为):
mock_open.side_effect = open # 注意是函数对象,不是字符串 - 误用
return_value=Exception()不会抛异常,只是返回一个异常实例
async 函数被 patch 后仍同步执行?
pytest-mock 默认不处理协程。如果你 patch 的是一个 async def 函数,mock 对象本身不是协程,直接 await 会报 TypeError: object MagicMock can't be used in 'await' expression。
- 正确做法:给 mock 设置
return_value为协程对象,或用AsyncMock(Python 3.8+):mock_fetch = AsyncMock(return_value={'data': 1})<br>with patch('api.fetch_data', new=mock_fetch):<br> result = await handler() - 旧版本可用
mock.AsyncMock(需安装mock包)或手动构造:return_value = asyncio.Future(); future.set_result(...) - 别用
patch(..., new_callable=MagicMock)去 mock async 函数,它不会变成协程
最容易被忽略的是 patch 路径和 async mock 类型的匹配——写对路径只是第一步,async 场景下必须显式使用协程感知的 mock 类型,否则 patch 成功了,调用时依然失败。

















