【问题标题】:NUnit AreEqual always returns falseNUnit AreEqual 总是返回 false
【发布时间】:2011-04-23 04:17:49
【问题描述】:
我确定我在这里遗漏了一些简单的东西,但我无法弄清楚为什么我的 NUnit 对象比较测试继续失败。
我有一个简单的对象:
public virtual int Id { get; private set; }
public virtual string Description { get; set; }
public virtual string Address { get; set; }
public virtual string Ports { get; set; }
public virtual string Password { get; set; }
public virtual ServerGroup ServerGroup { get; set; }
我将这个对象的一个实例保存到我的数据库中,然后使用 NHibernate 将其取出。我的 NUnit 单元测试将保存的对象与检索到的对象进行比较并进行比较。我知道 AreSame() 会失败,因为它们对对象的引用不同,但我希望 AreEqual() 通过。
如果我调试测试,我可以看到两个对象在这些属性中似乎具有相同的值,我的测试仍然失败。谁能告诉我为什么?
谢谢!
【问题讨论】:
标签:
unit-testing
nhibernate
nunit
【解决方案1】:
你必须在你的类上覆盖Equals() 方法。否则,NUnit 将使用基础实现,它比较引用(这肯定不是你在这里所追求的)
【解决方案2】:
您确实需要按照 Grzenio 的建议覆盖 Equals,但要注意 NHibernate 可能出现的细微混淆。具体来说,当启用延迟加载时,类型比较测试可能会失败。为了说明,这里有一段写得很好的 Equals 方法:
// override object.Equals
public override bool Equals(object obj)
{
//
// See the full list of guidelines at
// http://go.microsoft.com/fwlink/?LinkID=85237
// and also the guidance for operator== at
// http://go.microsoft.com/fwlink/?LinkId=85238
//
if (GetType() != obj.GetType())
{
return false;
}
....
}
但是当启用延迟加载时,NHib 的工作方式是生成实际对象的代理(从而推迟不必要的数据库命中)。如果在一个已被 NHib“代理”的对象和另一个未被“代理”的对象之间进行相等性检查,则会因为类型不匹配而失败。解决方案(由S#arp Architecture project 提供,将类型测试修改为如下所示:
public override bool Equals(object obj) {
...
if (GetType() != obj.GetTypeUnproxied())
{
return false;
}
...
}
protected virtual Type GetTypeUnproxied() { return GetType(); }
这在所有情况下都有效地返回底层对象的类型,即使 compareTo 对象是 NIB 代理。
Equals 方法可能很棘手,因为正确处理很重要,因此理想情况下,您可以将其分解为某种层超类型 (Fowler)。许多开源项目,包括我之前提到的 S#arp 项目,都提供了如何做到这一点的示例。
HTH,
贝瑞尔
【解决方案3】:
按照建议,您需要覆盖 Equals。您确实需要注意副作用。
您还应该覆盖 GetHashCode,否则您最终可能会得到 .Equals 为 true 的对象,但使用您的 Id 类作为 Dictionary 中的键,哈希将不匹配,从而导致多个条目具有“Equal”ID。
此外,您需要覆盖 == 和 != 运算符以保持一致的行为。
想象一下,如果 .Equals 为真但 == 为假,会出现什么混乱。