mock.patch 失效主因是作用域和启动时机不匹配,必须确保 patch 在实际调用发生的作用域内生效,且路径需严格对应导入位置而非定义位置。

mock.patch 为什么没生效?作用域和启动时机最关键
mock.patch 失效的常见原因是它只在被装饰或上下文管理的代码块内起作用,一旦跳出作用域,原始对象就恢复。比如在类方法里 patch 了 requests.get,但调用发生在 setUp 里,而测试方法里没触发——那 mock 根本没被用上。
实操建议:
- 优先用上下文管理器写法:
with mock.patch('requests.get') as mock_get:,清晰可控 - 装饰器方式必须确保装饰的是实际调用目标函数的层级,比如被测函数在
utils.py,就得@mock.patch('utils.requests.get'),而不是@mock.patch('requests.get') - 如果 patch 类,注意是 patch「导入位置」,不是定义位置:
from mypkg import service→ 要 patch'mypkg.service.SomeClass',不是'mypkg.SomeClass'
return_value 和 side_effect 怎么选?看返回逻辑是否固定
return_value 适合返回静态值,比如固定 JSON 字典;side_effect 用于需要动态行为的场景,比如抛异常、按调用次数返回不同结果、或执行真实函数逻辑后 mock。
常见错误:用 return_value={'status': 'ok'} 模拟一个会多次调用并返回不同响应的 API,结果每次都是同一个字典——这会掩盖状态变更 bug。
实操建议:
- 返回简单结构体:直接用
return_value,如mock_get.return_value.json.return_value = {'id': 123} - 需要模拟失败重试:用
side_effect=[ConnectionError, Mock(json=lambda: {'id': 456})] - 想验证参数又返回值:用函数形式
side_effect=lambda url, **kw: Mock(json=lambda: {'url': url})
如何安全地 mock 时间相关函数(time.time / datetime.now)?
直接 patch time.time 或 datetime.datetime.now 容易出兼容问题,尤其当被测代码用了 from datetime import datetime 这种导入方式时,patch 点必须严格匹配导入路径。
更稳妥的做法是 patch 被测模块中「实际使用的名称」。例如:
from datetime import datetime
def get_timestamp():
return datetime.now().isoformat()
要 mock 就得写 @mock.patch('mymodule.datetime'),然后在测试里设 mock_datetime.now.return_value = datetime(2023, 1, 1)。
实操建议:
- 避免 patch 内置模块顶层名(如
time),优先 patch 被测文件里 import 的别名或模块名 - 用
freeze_time第三方库更省心,但它引入了额外依赖,纯 unittest 场景下还是原生 mock 更轻量 - mock 后记得检查返回类型是否符合预期——比如
datetime.now()返回datetime实例,不能只 mock 成字符串
集成测试里 mock 太多,是不是设计出了问题?
当一个测试里要 patch 超过 3 个外部依赖(比如数据库、缓存、HTTP 客户端、消息队列),说明被测单元职责过重,或者边界不清晰。mock 不是补丁,而是接口契约的显式声明。
这时候该做的不是加更多 patch,而是审视:这个函数到底该不该承担这么多协作?能不能把 HTTP 调用抽成独立 service,把数据库操作封装进 repository?
实操建议:
- 每个测试只 mock 直接依赖,不 mock 依赖的依赖(比如 A 调 B,B 调 C,测试 A 时只 mock B,让 B 真实运行)
- 用
autospec=True参数:如mock.patch('requests.get', autospec=True),能防止调用不存在的方法,提前暴露接口误用 - mock 对象本身也是“可测对象”——检查
mock_get.assert_called_once_with(url='https://api.example.com')比检查返回值更能确认集成逻辑正确
mock 的粒度和位置,本质上反映的是代码的解耦程度。越难 mock,往往说明越该重构。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











