如何在非pytest环境中实现对象不等时的美观差异打印?
实现Pydantic对象的美观差异断言输出(非pytest环境)
在非pytest驱动的集成测试中,想要实现类似pytest的Pydantic对象差异美观打印,可以通过以下几种方式实现:
方法1:复用pytest的差异对比逻辑
pytest的断言差异输出依赖内部的_pytest.assertion.util模块,我们可以直接调用它来生成一致的差异格式:
from pydantic import BaseModel from _pytest.assertion.util import assertrepr_compare class Foo(BaseModel): id: str other_thing: str def assert_pydantic_equal(a, b): if a != b: # 调用pytest的差异生成函数 diff_lines = assertrepr_compare('==', a, b) raise AssertionError('\n'.join(diff_lines)) # 测试调用 oneFoo = Foo(id="red", other_thing="blue") twoFoo = Foo(id="red", other_thing="green") assert_pydantic_equal(oneFoo, twoFoo)
运行后会输出和pytest几乎一致的错误信息,包括高亮的差异标记。
方法2:手动实现Pydantic字段差异对比
如果不想依赖pytest的内部模块,可以自己遍历Pydantic对象的字段生成差异:
from pydantic import BaseModel def generate_pydantic_diff(a: BaseModel, b: BaseModel) -> str: if type(a) != type(b): return f"类型不匹配: {type(a).__name__} vs {type(b).__name__}" diff_content = ["Full diff:"] model_name = type(a).__name__ for field in a.model_fields: val_a = getattr(a, field) val_b = getattr(b, field) if val_a != val_b: # 生成类似pytest的差异行 prefix_len = len(model_name) + 4 + len(field) + 2 diff_content.append(f"- {model_name}(..., {field}={repr(val_b)}, ...)") diff_content.append(f"? {' ' * prefix_len} ^^^") diff_content.append(f"+ {model_name}(..., {field}={repr(val_a)}, ...)") diff_content.append(f"? {' ' * prefix_len} ^^^") diff_content.append("") return '\n'.join(diff_content) def assert_pydantic_equal(a, b): if a != b: error_msg = f"assert {a} == {b}\n\n{generate_pydantic_diff(a, b)}" raise AssertionError(error_msg) # 测试调用 oneFoo = Foo(id="red", other_thing="blue") twoFoo = Foo(id="red", other_thing="green") assert_pydantic_equal(oneFoo, twoFoo)
这种方式完全独立,适合没有安装pytest的环境。
方法3:使用第三方库DeepDiff
DeepDiff是专门用于对比复杂对象的库,能生成结构化的差异输出:
首先安装依赖:
pip install deepdiff
然后编写断言函数:
from pydantic import BaseModel from deepdiff import DeepDiff def assert_pydantic_equal(a: BaseModel, b: BaseModel): # 对比Pydantic对象的字典表示 diff = DeepDiff(a.model_dump(), b.model_dump(), verbose_level=2) if diff: error_msg = f"assert {a} == {b}\n\nFull diff:\n{diff.pretty()}" raise AssertionError(error_msg) # 测试调用 oneFoo = Foo(id="red", other_thing="blue") twoFoo = Foo(id="red", other_thing="green") assert_pydantic_equal(oneFoo, twoFoo)
它支持嵌套对象、列表、字典等多种结构的对比,输出格式清晰易读。
内容的提问来源于stack exchange,提问作者sixtyfootersdude
相关产品推荐
相关产品推荐

