Assert.AreEqual不会在IEnumerable实现上使用我的.Equals覆盖

时间:2012-05-24 12:07:03

标签: nunit ienumerable assert

我有一个PagedModel类,它实现IEnumerable只返回ModelData,忽略了分页数据。我还重写了Equals和GetHashCode,以允许比较两个PagedModel对象的ModelData,PageNumber,TotalPages和PageSize。

这是问题

Dim p1 As New PagedModel() With {
    .PageNumber = 1,
    .PageSize = 10,
    .TotalPages = 10,
    .ModelData = GetModelData()
}

Dim p2 As New PagedModel() With {
    .PageNumber = 1,
    .PageSize = 10,
    .TotalPages = 10,
    .ModelData = GetModelData()
}

p1.Equals(p2) =====> True
Assert.AreEqual(p1, p2) ======> False!

看起来NUnit正在调用它的内部EnumerableEqual方法来比较我的PagedModel而不是使用我提供的Equals方法!有没有办法覆盖这种行为,或者我是否必须编写自定义断言。

2 个答案:

答案 0 :(得分:11)

做你想要的事情:我会反对它,但如果你真的不喜欢NUnit的行为并想要自定义断言,你可以提供自己的EqualityComparer。

Assert.That(p1, Is.EqualTo(p2).Using(myCustomEqualityComparer));

你应该做什么(简答):你需要GetHashCode并且等于ModelData而不是PagedModel,因为你使用PagedModel作为集合而ModelData作为元素。

你应该做什么(长答案): 您需要在ModelData上实现Equals(object),而不是覆盖PagedModel上的IEquatable<T>,其中T是IEnumerable的类型参数,并覆盖GetHashCode()。这两个方法是.Net中的所有IEnumerable方法在使用Default Equality Comparer时用来确定相等性(对于诸如Union,Distinct等操作)(你没有指定自己的IEqualityComparer)。 />

  

[Default Equality Comparer]检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer。否则,它返回一个EqualityComparer,它使用由T提供的Object.Equals和Object.GetHashCode的覆盖。


要正常运行,GetHashCode需要为.Equals(T)返回true的所有对象返回相同的结果。反过来不一定正确 - GetHashCode可以返回不相等的对象的冲突。 More information here - see Marc Gravel's accepted answer。我还发现在使用素数的答案中GetHashCode的实现非常有用。

答案 1 :(得分:1)

如果你看一下GIT repo中NUnit相等比较器的实现,你会看到有两个枚举的专用比较块,它具有更高的优先级(仅仅因为它放在更高的位置) )使用IEquatable<T>界面或Object.Equals(Object)方法comparisons,而PagedModel类已在IEnumerable<ModelData>类中实现或重载。

我不知道这是一个错误还是一个功能,但你可能应该首先问自己,如果你的PagedModel类直接实现PagedModel接口实际上是最好的选择,尤其是因为您的ModelData不仅仅是ModelData个实例的枚举。

通过IEnumerable<ModelData>类的简单只读PagedModel属性提供PagedModel枚举可能就足够了(甚至更好)。 NUnit将停止查看您的ModelData对象,就像在IComparer个对象的简单枚举中一样,您的单元测试将按预期运行。

唯一的另一种选择是csauve提出的选择;为您的PagedModel实现一个简单的自定义PagedModel,并为所有断言提供一个实例,您将比较两个internal class PagedModelComparer : System.Collections.IComparer { public static readonly IComparer Instance = new PagedModelComparer(); private PagedModelComparer() { } public int Compare( object x, object y ) { return x is PagedModel && ((PagedModel)x).Equals( y ); } } ... [Test] ... Assert.That( actual, Is.EqualTo( expected ).Using( PagedModelComparer.Instance ) ); ... 个实例:

PagedModel

但是这会使你的测试变得比必要的更复杂,而且每当你为{{1}}编写额外的测试时,你总是要考虑使用你的特殊比较器。