直接用 assert 比较嵌套字典会失败,因为 python 的 == 对字典做浅层结构+值比较,但浮点精度误差、datetime 时区/微秒差异、nan 或 json 键序不定会导致意外报错且错误信息不明确。

为什么直接用 assert 比较嵌套字典会失败
因为 Python 的 == 对字典做浅层结构+值比较,但一旦嵌套中含 float(浮点精度误差)、datetime(时区/微秒差异)、NaN、或顺序不敏感的键(如 JSON 解析后键序不定),assert a == b 就会意外报错,且错误信息只显示“False”,看不出哪一层、哪个 key 不符。
用 pytest-approx 处理浮点字段差异
当嵌套字典里有 score: 0.1 + 0.2 这类计算结果(实际是 0.30000000000000004),直接比会失败。不用自己写容差逻辑,装个轻量扩展就行:
pip install pytest-approx
然后在断言中用 approx 包裹预期值:
from pytest import approx
<p>response = {"user": {"id": 123, "score": 0.30000000000000004}}
assert response["user"]["score"] == approx(0.3)</p>
-
approx()默认容差是1e-6,可传abs=1e-3调整 - 只对数字生效,嵌套里的字符串、列表仍走原生比较
- 不能用于整个字典,只能逐字段断言数值型叶子节点
用 deepdiff 获取精准差异定位
当需要知道“到底哪里不一样”,又不想手写递归比对时,DeepDiff 是最省心的选择。它返回结构化差异,直接告诉你哪个 key 缺失、哪个值变了、类型是否不一致:
pip install deepdiff
from deepdiff import DeepDiff
<p>a = {"data": {"items": [{"id": 1, "name": "foo"}], "total": 1.0}}
b = {"data": {"items": [{"id": 1, "name": "bar"}], "total": 1.0000001}}</p><p>diff = DeepDiff(a, b, ignore_order=True, report_repetition=True)
print(diff.get('values_changed', {})) # {'root["data"]["items"][0]["name"]': {'old_value': 'foo', 'new_value': 'bar'}}</p>
-
ignore_order=True忽略 list 中元素顺序(比如 API 返回的 items 无序) -
report_repetition=True报告重复项变化(避免漏掉数量差异) - 注意:
DeepDiff不处理函数、不可哈希对象,遇到会跳过并警告
自定义断言函数封装常见校验模式
如果项目里反复出现某类嵌套结构(如统一响应格式 {"code": 0, "data": {...}, "msg": "ok"}),硬套 DeepDiff 或逐字段写 approx 很啰嗦。写一个薄封装更可控:
def assert_api_response(actual, expected_data=None, code=0, msg="ok"):
assert actual.get("code") == code
assert actual.get("msg") == msg
if expected_data is not None:
from deepdiff import DeepDiff
diff = DeepDiff(actual.get("data", {}), expected_data, ignore_order=True)
assert not diff, f"Data mismatch:\n{diff}"
<h1>使用</h1><p>assert_api_response(resp, expected_data={"user": {"id": 123}}, code=0)</p>
- 把固定字段(
code/msg)和可变数据(data)分离校验 - 错误信息带
DeepDiff输出,一眼定位问题路径 - 避免在每个测试里重复 import 和参数设置
真正复杂的嵌套(比如含循环引用、自定义对象、大量 NaN)得先清理再比——没人能靠一个断言函数兜底所有情况,关键是要让失败时的信息指向具体字段,而不是卡在“AssertionError: False”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











