【稳健之道】第二篇:Mock 的艺术 —— 隔离外部世界的“混沌”

📅 发布时间:2026/7/13 7:08:53 👁️ 浏览次数:
【稳健之道】第二篇:Mock 的艺术 —— 隔离外部世界的“混沌”
专栏进度02 / 03 (测试进阶专题)单元测试的灵魂在于 “孤立”。如果一个测试因为对方服务器挂了而失败那这个测试就失去了意义。Mock模拟的本质就是用一个“假对象”替换掉“真依赖”让测试只关注你写的逻辑本身。一、 核心概念什么是 Patch在 Python 中unittest.mock.patch 是最常用的工具。它像是一个临时的“偷梁换柱”魔术在测试运行期间强行改变某个模块或函数的指向。场景你要测试一个天气预报函数它依赖于一个真实的 HTTP 请求。weather.pyimportrequestsdefget_weather_advice(city):# 这个请求是不可控的可能超时可能返回 404responserequests.get(fhttps://api.weather.com/{city})ifresponse.json()[weather]Rain:return记得带伞return天气不错test_weather.pyfromunittest.mockimportpatchfromweatherimportget_weather_advicepatch(weather.requests.get)deftest_get_weather_advice(mock_get):# 配置 Mock 对象的返回内容伪造一个下雨的 JSONmock_get.return_value.json.return_value{weather:Rain}resultget_weather_advice(Shanghai)assertresult记得带伞# 还可以验证requests.get 是否真的被调用了参数对吗 mock_get.assert_called_once_with(https://api.weather.com/Shanghai)二、 进阶技巧Side Effect副作用有时候仅仅返回一个固定值是不够的。你需要 Mock 对象表现得更“真实”比如第一次调用成功第二次调用抛出异常。deftest_api_retry_logic(mock_get):# 模拟第一次超时错误第二次返回正常mock_get.side_effect[TimeoutError(连接超时),{status:200}]# 这里可以编写并测试你的重试逻辑代码...三、 避坑指南Patch 到底该 Patch 谁这是 Mock 中最经典的坑“Patch 应该发生在对象被查找的地方而不是被定义的地方。”错误做法如果你在 weather.py 中写了 from requests import get然后你去 patch requests.get测试会失效。因为 weather 模块已经持有了原始 get 函数的引用。做法始终 patch 你的业务代码中引用的那个路径即 patch(‘weather.requests’) 或 patch(‘weather.get’)。四、 为什么要克制使用 MockMock 虽好但不能贪杯。Mock 过度会导致测试虚假通过你 mock 了一个返回值为 {“id”: 1}但真实 API 升级后返回的是 {“user_id”: 1}你的测试依然是绿的但程序上线就崩了。测试维护成本变高当代码重构、变量名改变时你得同步修改大量的字符串路径 patch。建议只对外部 API、数据库、文件系统、时间函数等“不可控因素”进行 Mock。