如何在Pytest中检查两个同类型对象的内容是否相等?
嘿,这个问题我之前写测试的时候也碰到过,太有共鸣了!来给你捋捋清楚:
首先:默认的assert obj1 == obj2行不行?
答案是不行——除非你给你的类做了特殊处理。
Python里默认的==比较逻辑继承自object类的__eq__方法,它本质上是在判断两个对象是不是同一个内存地址的实例(也就是id(obj1) == id(obj2))。哪怕两个对象的所有属性完全一样,只要它们是分开创建的不同实例,默认的==都会返回False,自然会触发AssertionError。
那有哪些简便的解决办法?
1. 用Python 3.7+的dataclass(最推荐!)
如果你用的是Python3.7及以上版本,直接用dataclasses模块的装饰器,它会自动帮你生成__eq__方法,自动比较所有定义的字段:
from dataclasses import dataclass @dataclass class YourTestClass: name: str value: int flag: bool
这样你直接写assert obj1 == obj2,就会自动比较name、value、flag这三个属性是否全部相等,完全不用自己写一行比较代码,省心又不容易出错。
2. 手动实现__eq__方法(兼容旧Python版本)
如果你的项目还在用Python3.7以下的版本,或者没法用dataclass,那可以给类手动实现__eq__这个“富比较”方法:
class YourTestClass: def __init__(self, name, value, flag): self.name = name self.value = value self.flag = flag def __eq__(self, other): # 先判断是不是同类型的对象 if not isinstance(other, YourTestClass): return NotImplemented # 比较所有需要验证的属性 return (self.name == other.name and self.value == other.value and self.flag == other.flag)
如果你的类属性特别多,也可以偷懒用self.__dict__ == other.__dict__(__dict__存储了对象的所有实例属性),不过要注意:如果类里有私有属性(比如_private_attr)或者继承来的属性,这个方法可能会有问题,需要根据实际情况调整。
3. 临时测试:直接比较属性或字典
如果你只是临时写测试,不想修改原类的代码,也可以在测试用例里直接比较:
- 逐个属性比较:
assert obj1.name == obj2.name、assert obj1.value == obj2.value...(属性少的时候还行,多了就麻烦) - 直接比较属性字典:
assert obj1.__dict__ == obj2.__dict__,这样断言失败时,Pytest会帮你显示两个字典的差异,方便快速定位问题。
额外提一句:Pytest的辅助技巧
如果用Pytest的话,当你用assert obj1 == obj2且类实现了__eq__,Pytest会自动帮你生成更友好的断言失败提示。要是你想自定义提示,还可以用pytest_assertrepr_compare钩子,但一般来说前面的方法已经足够用了。
内容的提问来源于stack exchange,提问作者maln0ir

