我已经看过很多说明(Why does Assert.AreEqual(T obj1, Tobj2) fail with identical objects,Unit Test Assert.AreEqual failed,Assert.AreEqual fails with the same type)来为我的课程实施Equals
/ IEqualityComparer
,如果我想查看基于字段值而不是引用的相等性。
试图这样做,我无法让它工作,并将问题缩小到以下。
我的班级主题需要进行测试。在 SubjectTestEqual 中,我希望两个实例相等,但结果是“Assert.AreEqual失败。另外,如果我调试代码,我看不到对 Equals 的调用也不是 GetHashCode 。
基于神秘的“Default属性检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer。否则,它返回使用Object.Equals和Object的覆盖的EqualityComparer .GetHashCode由T.提供。“在EqualityComparer.Default Property documentation中,我也尝试使用IEquatable(取消注释代码来查看效果)无济于事。
public class Subject : IEqualityComparer<Subject>//, IEquatable<Subject>
{
public int Id { get; set; }
public Subject(int name) { Id = name; }
public bool Equals(Subject x, Subject y)
{ return (x.Id == y.Id); }
public int GetHashCode(Subject obj)
{ return Id; }
//public bool Equals(Subject other)
//{ return Equals(this, other); }
}
[TestClass]
public class SubjectTest
{
[TestMethod]
public void SubjectTestEqual()
{ Assert.AreEqual<Subject>(new Subject(1), new Subject(1)); }
[TestMethod]
public void SubjectTestSame()
{
Subject test = new Subject(1);
Assert.AreEqual<Subject>(test, test);
}
}
任何人都可以对此有所了解吗?
答案 0 :(得分:5)
你必须覆盖基本方法才能打电话给你:
public override bool Equals(object obj)
{ ... }
public override int GetHashCode()
{ ... }
但您必须应用与Equals
和GetHashcode
基本方法相同的签名。
答案 1 :(得分:1)
感谢您的回答,他们进一步帮助了我,但他们都没有完全帮助我。
如果我覆盖像这样的对象的Equals和GetHashCode方法:
public override bool Equals(object obj)
{ return true; }
public override int GetHashCode()
{ return 0; }
调用方法,我的测试将成功。但是,当然,我不想为类型对象的参数实现这些方法。为什么我的班级会将实例与任何对象实例进行比较?
因此,我将此方法修改为静态:public **static** bool Equals(Subject x, Subject y)
并引入了一种新的测试方法(为简洁起见,所有测试都在一个方法中):
[TestMethod]
public void SubjectTestWithSubjectEquals()
{
Assert.IsTrue(Subject.Equals(new Subject(1), new Subject(1)));
Assert.IsTrue(new Subject(1).Equals(new Subject(1)));
Assert.IsFalse(Subject.Equals(new Subject(1), new Subject(2)));
Assert.IsFalse(new Subject(1).Equals(new Subject(2)));
}
这些测试将成功。但是,我不确定这是否是一个好的方法。首先,要使Assert.IsTrue((new Subject(1)) == (new Subject(1)));
成功,我需要实施:
public static bool operator ==(Subject x, Subject y)
{ return Equals(x, y); }
并且还要求:
public static bool operator !=(Subject x, Subject y)
{ return !Equals(x, y); }
此外,更进一步,希望能够比较主题类型的列表,我尝试了这个测试:
[TestMethod]
public void SubjectTestWithCollections()
{
var list1 = new List<Subject>() { new Subject(1), new Subject(2) };
var list2 = new List<Subject>() { new Subject(1), new Subject(2) };
CollectionAssert.AreEqual(list1, list2);
}
这将失败,显然,每个项目将使用Assert.AreEqual而不是Subject.Equals进行比较。我见过issues with CollectionAssert.AreEquivalent,这让我想知道这是否主要是由于Microsoft.VisualStudio.TestTools.UnitTesting的实现方式造成的,或者我不应该试图通过Equals来解决这个问题。
答案 2 :(得分:0)
您的TestClass违反了Object.Equals
的合同。 Assert.AreEqual
非常合理地依赖合同。
文档状态(在要求列表中):
x.Equals(null引用(在Visual Basic中为Nothing))返回false。
答案 3 :(得分:0)
Assert.AreEqual
将专门使用传入的第一个参数的Equals
方法。它现在已了解您的IEqualityComparer
实现,因此不会使用它。
通常,当一个类需要比较对象是否相等时,它将有一个IEqualityComparer
的可选参数,该类可以用来进行比较而不是对象本身的Equals
方法,但是Assert.AreEqual
不接受此类参数。这意味着要使用Assert.AreEqual
,您需要覆盖从Equals
继承的object
方法,即:
public override bool Equals(object obj){}
对于一个类型实现它自己的类型的IEqualityComparer
没有多大意义。 IEqualityComparer
的想法是它允许您比较其他类型的是否相等,而不是“你自己”。