mock 是精准隔离外部依赖的工具,用于确保测试只验证自身逻辑;必须 mock 不可控、不稳定、未就绪或高成本依赖,如第三方 API、数据库连接、未完成服务及非确定性行为。

mock不是用来“覆盖更多代码行”的装饰品,而是用来**精准隔离外部依赖、让测试只验证你写的逻辑**。用错方式反而会让测试变脆、掩盖真实缺陷。
什么时候必须用 mock?不是所有 HTTP 调用都要 mock
真正该 mock 的是那些「不可控、不稳定、未就绪或成本过高」的依赖,比如:
-
requests.get或requests.post调用第三方 API(如支付、短信、天气) - 数据库连接(
sqlite3.connect、psycopg2.connect)在单元测试中应被替换,而非真实建库 - 调用尚未开发完成的内部服务(例如
user_service.get_profile()) - 依赖当前时间、随机数、文件系统读写等非确定性行为
反例:对一个纯内存计算函数(如 calculate_discount())做 mock,毫无意义——它没依赖,mock 只是增加噪声。
patch 和 Mock 到底该选哪个?
关键看你要替换的对象在哪儿被使用,而不是在哪儿被定义。
- 用
@patch('requests.get'):当被测函数里直接写了requests.get(...) - 用
@patch('my_module.requests.get'):如果被测模块叫my_module.py,且它 import 了requests,那你必须 patch 它**导入的位置**,不是源位置 - 直接赋值
requests.get = Mock(...)是危险的——它污染全局状态,多个测试可能互相干扰 -
Mock(return_value=...)适合简单返回;需要校验调用参数时,必须用side_effect或后续断言mock_obj.assert_called_with(...)
常见错误:@patch('requests.get') 写对了,但被测函数实际调用的是 session.get() —— 这时候得 patch requests.Session.get 或更细粒度地 patch 实例方法。
mock 返回异常响应,别只 return 一个 dict
很多测试只 mock 成功路径(如 return_value={'status': 'ok'}),却漏掉网络异常、超时、4xx/5xx 状态码等关键分支。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
- 模拟网络异常:
side_effect=requests.exceptions.ConnectionError('timeout') - 模拟特定状态码:
return_value=Mock(status_code=500, json=lambda: {'error': 'server error'}) - 模拟重定向或多次调用:
side_effect=[Mock(status_code=302), Mock(status_code=200)] - 别忘了检查是否真的抛出了异常:
with self.assertRaises(requests.exceptions.HTTPError): ...
如果你的业务逻辑里有 res.raise_for_status(),不 mock 异常就永远走不到 except 分支,这部分逻辑等于没测。
mock 之后忘记 assert 调用细节,等于白 mock
只写 mock_get = Mock(return_value=...),却不验证它是否被以正确参数调用过,测试就只是“跑通”,不是“验证行为”。
- 必须加断言:
mock_get.assert_called_once_with('https://api.example.com/user/123', timeout=5) - 用
assert_called_with比assert_called_once更严格,能捕获参数错误 - 如果函数里用了
**kwargs或构造了动态 URL,记得 inspectmock_get.call_args或call_args_list - mock 对象默认允许任意属性访问(
mock_obj.nonexistent_attr不报错),容易掩盖拼写错误——开启spec或spec_set=True可提前暴露问题
最易忽略的一点:mock 对象默认不会校验参数类型或结构。比如你 mock 了一个返回字典的接口,但测试里误用了 res['data']['id'],而真实接口返回的是 res['user_id'],这种字段名差异只有在集成测试或线上才暴露——mock 本身不会提醒你。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










