用 pytest + requests 测试需先断言状态码再解析 JSON,避免 JSONDecodeError;验证结构应检查关键字段存在及类型,而非全量相等;所有请求须设 timeout,异常响应需按状态码分类处理。

怎么用 pytest + requests 写一个能验状态码和 JSON 结构的测试
直接上手:核心是用 requests.get()(或 post 等)发请求,再用 assert 检查 r.status_code 和 r.json()。pytest 只负责运行和报错,不参与 HTTP 通信。
常见错误现象:r.json() 报 JSONDecodeError —— 说明接口返回了非 JSON 内容(比如 HTML 错误页、空响应、502/404 的纯文本),必须先检查状态码再解析 JSON。
- 永远先断言
r.status_code == 200(或预期码),再调r.json() - 不要用
response.text手动解析 JSON,r.json()自带校验且更简洁 - 如果接口可能返回 204 或空 body,加
if r.content:判断再调.json()
验证 JSON 返回结构时,为什么不能直接 assert 字典相等
因为真实 API 响应常含动态字段(如 "id": 123、"created_at": "2024-05-..."),全字段比对会频繁失败。重点应是“关键字段存在且类型正确”,不是“完全一致”。
使用场景:你只关心 {"data": {"name": str, "price": float}, "code": int} 这类契约,而非具体值。
立即学习“Python免费学习笔记(深入)”;
- 用
isinstance(r.json()["data"]["name"], str)替代== "test" - 用
"data" in r.json()和"code" in r.json()先保字段存在 - 嵌套深时,推荐提取成小函数,比如
assert_data_shape(r.json()),避免测试体臃肿
pytest 参数化测试多个 URL 或参数组合时要注意什么
用 @pytest.mark.parametrize 很方便,但容易忽略两点:一是请求未加超时,卡住整个测试;二是并发跑时没控制请求数,被目标服务限流或拒绝。
仅使用 Python 将 Claw Code 虚拟化框架与 OpenClaw 集成,提供 184 种工具和 200 多条命令,用于安全分析和代码质量...
性能 / 兼容性影响:本地开发时默认无超时,CI 环境网络波动会导致随机失败。
- 所有
requests调用必须显式传timeout=(3, 7)(连接 3 秒,读取 7 秒) - 避免在 parametrize 中直接写死
requests.get(...),应把请求逻辑封装进函数,便于复用和 mock - 若需测鉴权接口,token 应从 fixture 获取,而不是写死在参数列表里
遇到 401/403 却收不到 JSON 错误体怎么办
很多接口在认证失败时不返回标准 JSON,而是返回空 body 或 HTML 页面,此时 r.json() 必然抛异常,导致测试中断而非断言失败。
正确做法是捕获异常,并根据状态码分支处理:
try:
data = r.json()
except ValueError: # requests 2.x 用这个,3.x 改为 json.JSONDecodeError
data = {}
assert r.status_code == 401
assert "error" not in data or data.get("code") != 0 # 根据实际协议调整容易踩的坑:直接写 assert r.json()["error"],一碰到非 JSON 就报错退出,pytest 显示的是异常 traceback,不是你写的断言失败信息。
复杂点在于——每个状态码对应的响应格式可能不同,400 是 JSON,401 是空,500 是 HTML,得按码分类处理,不能一套逻辑走到底。

















