直接调用真实API会导致测试随机失败、变慢且无法覆盖边界情况;Mock通过patch替换requests调用,需按被测代码实际导入路径(如'myapp.views.requests')打桩,并构造含status_code和json方法的Mock响应对象。

为什么直接调用真实API会导致测试失败或变慢
单元测试里跑真实网络请求,会暴露三个致命问题:一是网络不稳定让测试随机失败;二是外部API响应时间波动拖慢整个测试套件;三是你无法控制返回数据,比如想测“用户不存在”这种边界情况时,真实服务可能根本不返回这种状态。Mock 的作用就是把 requests.get、requests.post 这类调用替换成可控的返回值,让测试只聚焦逻辑本身。
用 patch 替换目标模块中的函数,而不是导入位置
常见错误是 patch 写成 @patch('requests.get'),这其实没效果——Django 视图或服务里调用的是自己模块内导入的 requests,不是全局 requests 模块。必须按“被测试代码实际导入的位置”来 patch。比如你的视图在 myapp/views.py 里写了 import requests,那就要 patch 'myapp.views.requests';如果写的是 from requests import get,就得 patch 'myapp.views.get'。
- 查清楚被测函数里怎么引用 requests:打开对应 Python 文件,看 import 语句和调用方式
- patch 路径格式为
'package.module.function_name',不是'requests.get' - 使用
side_effect可模拟不同 HTTP 状态码,比如side_effect=[ConnectionError, Mock(status_code=200)]
构造符合实际结构的 Mock 响应对象
Django 视图通常依赖 response.json() 或 response.status_code,所以不能只 mock 返回字典,得 mock 一个带这些属性的对象。最稳妥的方式是用 Mock 构造一个类实例,手动设置 json 方法和 status_code 属性。
from unittest.mock import Mock
<p>mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"id": 123, "name": "test"}</p><p>@patch('myapp.services.requests.get', return_value=mock_response)
def test_api_success(self, mock_get):</p><h1>……</h1>- 别用
return_value={"data": ...},因为 dict 没有.json()方法 - 如果 API 返回非 JSON(比如 XML 或纯文本),要 mock
text属性而非json - 注意
json.return_value是方法调用,不是属性赋值,要用.return_value
测试异常路径时,patch 要覆盖所有可能出错点
真实调用中,requests 可能在连接阶段就抛 ConnectionError,也可能收到 4xx/5xx 状态但没 raise 异常(取决于是否调用 response.raise_for_status())。测试时得分别 mock 这两类行为。
立即学习“Python免费学习笔记(深入)”;
- 模拟连接失败:用
side_effect=ConnectionError或Timeout - 模拟 404 响应但不抛异常:设置
status_code=404,并确保被测代码没调raise_for_status() - 模拟 500 并触发异常:设
status_code=500+side_effect=lambda: mock_response.raise_for_status()
真实项目里,很多同学只测了 success case,漏掉对 except requests.RequestException: 分支的覆盖,结果上线后一连不上就崩。


















