Python3.7+下pytest如何校验dict插入顺序并输出友好差异结果?
问题描述
从Python 3.7版本开始,dict已被官方明确保证遵循插入顺序。我目前在使用pytest编写单元测试,需要比对两个dict的同时校验元素的插入顺序是否一致。
我的应用不会在3.7以下版本的Python环境运行,无需考虑向后兼容性。
核心问题
是否可以在pytest中直接对比普通dict,既保留顺序校验能力,又能输出友好的差异提示?
已尝试的无效方案
- 直接用
==对比dict:
a = {'x': 1, 'y': {'u': 3, 'v': 4}} b = {'y': {'v': 4, 'u': 3}, 'x': 1} assert a == b
这个断言会正常通过,但不符合预期:两个dict的值相等但插入顺序不一致。
- 递归转为
OrderedDict后对比:
from collections import OrderedDict def deep_ordered_dict(value): if isinstance(value, dict): value = OrderedDict(value) for k, v in value.items(): value[k] = deep_ordered_dict(v) if isinstance(value, list): for k, v in enumerate(value): value[k] = deep_ordered_dict(v) return value a = {'x': 1, 'y': {'u': 3, 'v': 4}} b = {'y': {'v': 4, 'u': 3}, 'x': 1} assert deep_ordered_dict(a) == deep_ordered_dict(b)
存在两个问题:
- 代码冗余不美观
- pytest输出的差异提示可读性很差
- 转为JSON字符串对比:
import json a = {'x': 1, 'y': {'u': 3, 'v': 4}} b = {'y': {'v': 4, 'u': 3}, 'x': 1} assert json.dumps(a, indent=2) == json.dumps(b, indent=2)
存在问题:
- pytest输出的差异提示可读性很差
解决方案
可以通过递归转换的方式实现需求,将dict按插入顺序转为嵌套的键值对列表后再做断言,pytest对列表类型的差异会输出直观的逐位对比提示,完全满足顺序校验和友好报错的要求。
示例代码如下:
def deep_to_ordered_pairs(obj): # 处理字典类型:转为按插入顺序排列的键值对列表 if isinstance(obj, dict): return [(k, deep_to_ordered_pairs(v)) for k, v in obj.items()] # 处理列表类型:递归处理每个元素 if isinstance(obj, list): return [deep_to_ordered_pairs(item) for item in obj] # 其他类型直接返回原值 return obj # 测试用例 a = {'x': 1, 'y': {'u': 3, 'v': 4}} b = {'y': {'v': 4, 'u': 3}, 'x': 1} assert deep_to_ordered_pairs(a) == deep_to_ordered_pairs(b)
该方案的优势:
- 无额外依赖,代码简洁易维护
- 完全遵循Python3.7+原生dict的插入顺序规则,嵌套结构也可以正常校验
- pytest输出的差异提示和原生列表对比完全一致,会明确标出哪一层的第几个键值对不匹配,可读性极强
如果需要频繁使用该校验逻辑,可以把转换函数封装到公共测试工具模块中,调用成本极低。
内容的提问来源于stack exchange,提问作者j123b567
相关产品推荐
相关产品推荐

