19

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

这就是问题所在

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 方法!有什么方法可以覆盖这种行为,还是我必须编写一个自定义断言。

4

2 回答 2

12

按照您的要求做:我建议您不要这样做,但如果您真的不喜欢 NUnit 的行为并且想要自定义断言,您可以提供自己的 EqualityComparer。

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

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

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

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


为了正常运行,GetHashCode 需要为所有为 .Equals(T) 返回 true 的对象返回相同的结果。反过来不一定正确 - GetHashCode 可以返回不相等对象的冲突。更多信息请参见 Marc Gravel 接受的答案。我还发现 GetHashCode 在那个答案中使用素数的实现非常有用。

于 2012-05-29T22:05:28.927 回答
1

如果你看一下GIT repo中 NUnit 相等比较器的实现,你会看到有一个用于两个枚举的专用比较块,它的优先级高于使用您在类中实现或重载的IEquatable<T>接口或方法。Object.Equals(Object)PagedModel

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

ModelData通过类的简单只读IEnumerable<ModelData>属性提供枚举可能就足够了(甚至更好)PagedModel。NUnit 将停止将您的PagedModel对象视为对象的简单枚举,ModelData并且您的单元测试将按预期运行。

唯一的其他选择是 csauve 建议的选择;IComparer为您实现一个简单的自定义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.

于 2015-04-10T21:42:47.453 回答