You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在pytest中断言含mock属性的两个Pydantic模型相等?

优雅处理Pydantic模型中忽略特定字段的断言测试

我明白你遇到的问题——当测试Pydantic模型列表时,总有一些动态计算的字段(比如你的est_time)不在测试范围内,直接用mock.ANY替代会因为类型/引用不匹配导致断言失败,而现在循环对比字典的写法又有点啰嗦。下面给你几个更简洁、符合Python风格的解决方案:

方案1:用Pydantic自带的exclude参数跳过字段

这应该是最直接的方案,利用Pydantic模型转字典时的exclude参数,直接忽略不需要校验的est_time字段:

expected_list = [
    Class.construct(
        student_id=student1.id,
        property=Property.A,
    ),
    Class.construct(
        student_id=student1.id,
        property=Property.B,
    )
]

for result, expected in zip(my_schedules, expected_list):
    # 排除est_time后再对比字典
    assert result.dict(exclude={"est_time"}) == expected.dict(exclude={"est_time"})

如果后续需要忽略多个字段,只需要在exclude的字典里添加对应的键即可,逻辑清晰且无需额外依赖。

方案2:自定义模型比较方法(适合频繁复用场景)

如果你的测试中经常需要忽略est_time做断言,可以给Class模型添加一个自定义的比较方法,把固定要校验的字段逻辑封装起来:

from pydantic import BaseModel
from datetime import datetime
from enum import Enum

class Property(Enum):
    A = "A"
    B = "B"

class Class(BaseModel):
    student_id: str
    property: Property
    est_time: datetime

    def matches_without_est_time(self, other: "Class") -> bool:
        """忽略est_time字段,对比其他核心属性"""
        return (
            self.student_id == other.student_id
            and self.property == other.property
        )

之后断言的时候就可以直接调用这个方法,代码更易读:

expected_list = [
    Class.construct(student_id=student1.id, property=Property.A),
    Class.construct(student_id=student1.id, property=Property.B),
]

for result, expected in zip(my_schedules, expected_list):
    assert result.matches_without_est_time(expected)

方案3:手动清理字典字段(轻量灵活)

如果不想修改模型也不想用Pydantic的参数,也可以直接在对比前删除est_time字段,写法同样简洁:

expected_list = [
    {"student_id": student1.id, "property": Property.A.value},
    {"student_id": student1.id, "property": Property.B.value},
]

for result, expected in zip(my_schedules, expected_list):
    result_dict = result.dict()
    del result_dict["est_time"]
    assert result_dict == expected

这里注意把枚举类型转成对应的值(比如Property.A.value),避免类型不匹配。

方案4:用pytest的approx处理动态时间(适合有微小误差的场景)

如果你的est_time是基于当前时间生成的,可能存在毫秒级的误差,这时候可以用pytest的approx来做近似对比:

from pytest import approx

expected_list = [
    Class.construct(
        student_id=student1.id,
        property=Property.A,
        est_time=datetime(2020,1,3),  # 预期的基准时间
    ),
    Class.construct(
        student_id=student1.id,
        property=Property.B,
        est_time=datetime(2020,1,4),
    )
]

for result, expected in zip(my_schedules, expected_list):
    # 转成时间戳后允许微小误差
    assert result.est_time.timestamp() == approx(expected.est_time.timestamp())
    # 其他字段直接对比
    assert result.student_id == expected.student_id
    assert result.property == expected.property

这个方案适合需要校验est_time大致范围,而不是完全忽略的场景。

总结

如果只是单纯忽略est_time字段,方案1是最简洁且符合Pydantic设计的选择;如果需要频繁做这类断言,方案2的复用性更好;方案3则是最轻量的临时写法。

内容的提问来源于stack exchange,提问作者zcahfg2

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 07:44:08