pytest断言字典用==足够,但深层嵌套含set、浮点精度、动态字段时会失败;应使用pytest-approx、deepdiff或自定义过滤函数处理容差与忽略逻辑。

pytest断言字典时直接用 == 就够了,但深层嵌套会失败
Python 的 dict 支持原生 == 比较,pytest 默认就靠它做断言。只要两个字典键值完全一致(包括嵌套结构),assert a == b 就能通过,且报错信息自带差异高亮——这是 pytest 的默认行为,不用额外配置。
但注意:如果字典里嵌了 set、自定义对象、或浮点数精度不一致,== 会直接返回 False,而 pytest 不会帮你递归标准化或容差比较。
- 嵌套字典中含
set:比如{"tags": {"a", "b"}}和{"tags": ["a", "b"]}永远不等,哪怕内容一样 - 浮点字段:API 返回的
"price": 19.99和你预期的19.990000000000002看似一样,==仍判为失败 - 顺序敏感:Python 3.7+ 字典保持插入顺序,但如果你用
json.loads()解析再和手动构造的 dict 比,key 顺序不同不影响==;可一旦混入OrderedDict或旧版本 Python,就可能出问题
需要忽略字段或容差比较时,别硬改 assert,用 pytest-approx 或自定义比较函数
硬在 assert 后面加 round() 或 json.dumps(..., sort_keys=True) 是临时补丁,不可维护。真正要忽略字段、跳过时间戳、容忍浮点误差,得把比较逻辑抽出来。
- 浮点容差:用
pytest-approx插件,assert resp["score"] == pytest.approx(95.5, abs=0.01) - 忽略字段:写个简易过滤函数,比如只比关心的 key:
assert {k: v for k, v in actual.items() if k in expected} == expected - 深度忽略:对嵌套结构,用
deepdiff库(非 pytest 内置),但要注意它不返回布尔值,需配合assert not DeepDiff(...)
别在测试里反复写 del data["updated_at"] —— 这类“清洗”动作应该封装成 fixture 或工具函数,否则每次断言前都要手动删,漏一个就失败。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
JSON 接口测试中,用 json.loads() 后直接 assert == 最常见也最稳妥
绝大多数 Web API 返回 JSON,用 requests.get(...).json() 得到的就是 dict,和你写死的预期字典结构一致。这时候 assert resp == expected_dict 是最快、最清晰的方式。
- 确保两边都是纯
dict/list:避免混入Decimal、datetime等非 JSON 原生类型,否则==一定失败 - 字符串编码:如果响应是 bytes,别忘了先
.decode("utf-8")再json.loads(),否则抛TypeError: the JSON object must be str, bytes or bytearray - 空值处理:
None在 JSON 中是null,Python 里就是None,两者相等;但数据库字段为空时可能返回""或[],需按实际接口约定写预期
assert 断言失败时,pytest 默认输出差异,但复杂嵌套下仍难定位
pytest 的 assert 重写机制确实会在失败时打印左右值 diff,对两层深的字典很友好。但一旦嵌套超过三层、或含大量字段,终端输出会刷屏,关键差异反而被淹没。
- 用
-vv参数让 pytest 输出更详细上下文,有时能多显示一层 key 路径 - 对超长响应,先用
pprint.pformat()格式化再断言,或拆成多个小断言,比如分别验证resp["data"]["user"]和resp["meta"]["count"] - 不要依赖 IDE 的“自动展开”功能来查字典差异——它可能缓存旧对象、或没显示
__dict__以外的属性,真实运行时看到的才是准的
最麻烦的是字段动态生成(如 ID、token、时间戳),这类字段没法写死预期,必须用正则匹配或存在性断言(assert "id" in resp),而不是硬塞进字典比较里。

















