如何重写含DateTime属性的对象Equals方法以通过单元测试?
问题分析
核心问题是Model类的Edited属性默认赋值为DateTime.Now,你创建expected对象的时间与getModel()返回result对象的时间存在微小时间差,导致Equals方法里的精确时间比较始终失败。
解决方案
方案1:统一测试中的时间值
你的初步方案思路可行,还可以优化得更清晰:要么用实际结果的时间构建预期对象,要么同步两个对象的时间值:
public void MyTest() { Model result = cut.getModel(); // 用实际结果的时间构建预期对象,彻底避免时间差 Model expected = new() { Id = 1, Editor = "Me", Edited = result.Edited }; Assert.AreEqual(expected, result); }
或者:
public void MyTest() { Model expected = new() { Id = 1, Editor = "Me"}; Model result = cut.getModel(); // 同步两个对象的时间值 expected.Edited = result.Edited; Assert.AreEqual(expected, result); }
方案2:修改Equals方法忽略Edited字段
如果Edited仅用于记录修改时间,不参与业务层面的对象相等判断,可以直接在Equals中移除该字段的比较逻辑:
public override bool Equals(object obj) { var myObj = obj as Model; if (myObj == null) return false; return myObj.Id == Id && myObj.Editor == Editor; // 移除Edited的比较逻辑 }
注意:这种修改必须符合业务需求,确保忽略时间字段不会影响其他场景的相等判断。
方案3:宽松的时间比较
如果需要保留时间比较但允许微小误差(比如毫秒级差异),可以调整Equals里的时间判断逻辑,验证时间差是否在可接受范围内:
public override bool Equals(object obj) { var myObj = obj as Model; if (myObj == null) return false; // 判断时间差是否在1秒内(阈值可根据需求调整) var timeDiff = Math.Abs((myObj.Edited - Edited).TotalMilliseconds); return myObj.Id == Id && myObj.Editor == Editor && timeDiff < 1000; }
方案4:逐个字段断言(更灵活)
放弃依赖重载的Equals,直接在测试中对关键字段分别断言,这种方式更直观,无需修改业务类逻辑:
public void MyTest() { Model expected = new() { Id = 1, Editor = "Me"}; Model result = cut.getModel(); Assert.AreEqual(expected.Id, result.Id); Assert.AreEqual(expected.Editor, result.Editor); // 如需验证时间,可做宽松判断 Assert.That(result.Edited, Is.EqualTo(DateTime.Now).Within(1).Seconds); }
内容的提问来源于stack exchange,提问作者Alberto Martín
相关产品推荐
相关产品推荐

