2

我正在尝试比较包含自定义对象的 2 个列表(包装在一个对象中)。我不关心顺序,但如果列表 1 包含“1,2,3,4”,那么列表 2 必须且仅包含这些元素。例如:“4,2,3,1”

基于比较两个 List<T> 对象是否相等,忽略顺序 忽略顺序我使用了 except 和 Any 但它没有给我想要的结果。

如果我使用Assert.Equals它失败,但Assert.IsTry(list1.equals(list2))成功。

此外,如果我删除 Equals 和 GetHashCode 实现,那么两个测试都会失败。

public class AppointmentCollection : List<Appointment>
{
    public override bool Equals(object obj)
    {            
        var appCol = obj as AppointmentCollection;

        if (appCol == null)
        {
            return false;
        }

        return (appCol.Count == this.Count) && !(this.Except(appCol).Any());
    }


    public override int GetHashCode()
    {
        unchecked
        {
            //use 2 primes
            int hash = 17;
            foreach (var appointment in this)
            {
                hash = hash * 19 + appointment.GetHashCode();
            }
            return hash;
        }
    }
}

public class Appointment
{
    public string Title {get; set;}
    public DateTime StartTime {get; set;}
    public DateTime EndTime { get; set;}

    public override bool Equals(object obj)
    {
        var appointment = obj as Appointment;
        if (appointment == null)
        {
            return false;
        }
        return Title.Equals(appointment.Title) &&
            StartTime.Equals(appointment.StartTime) &&
            EndTime.Equals(appointment.EndTime);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            //use 2 primes
            int hash = 17;
            hash = hash * 19 + Title.GetHashCode();
            hash = hash * 19 + StartTime.GetHashCode();
            hash = hash * 19 + EndTime.GetHashCode();
            return hash;
        }
    }
}

[Test]
public void TestAppointmentListComparisonDifferentOrder()
{
    var appointment1 = new Appointment(
        "equals test1",
        new DateTime(2013, 9, 4),
        new DateTime(2013, 9, 4));

    var appointment2 = new Appointment(
        "equals test2",
        new DateTime(2013, 9, 4),
        new DateTime(2013, 9, 4));

    var list1 = new AppointmentCollection() { appointment1, appointment2 };
    var list2 = new AppointmentCollection() { appointment2, appointment1 };

    //With Equals/GetHashCode in AppointmentCollection implemented
    CollectionAssert.AreEqual(list1, list2); //fails
    Assert.IsTrue(list1.Equals(list2)); //success

    //Without Equals/GetHashCode in AppointmentCollection implemented
    CollectionAssert.AreEqual(list1, list2); //fails
    Assert.IsTrue(list1.Equals(list2)); //fails
}
4

1 回答 1

5

您没有明确说明您使用哪种单元测试工具。也许CollectionAssert是类Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert,或者也许是类,或者NUnit.Framework.CollectionAssert其他什么?

所以检查你的测试工具的文档,或者在这里写下你使用的是哪一个。

然而,这很常见

CollectionAssert.AreEqual( ... );

检查集合是否以相同的顺序相同,而

CollectionAssert.AreEquivalent( ... );

会检查你想要什么。所以使用后者。

实际上,这两种方法都没有CollectionAssert使用您对Equals(object). 要使用它,请编写:

Assert.AreEqual( ... );

编辑:我认为Assert.AreEqual(exp, act);最终总是exp.Equals(act)会调用你的覆盖AppointmentCollection。但事实证明,我们以私有实例方法EqualConstraint.ObjectsEqual结束,并且正如人们所看到的那样,它检查运行时类型是否实现ICollection,在这种情况下,您的覆盖永远不会被使用。

经验教训:使用Assert.AreEqual可能会与集合混淆。使用CollectionAssert.AreEquivalentCollectionAssert.AreEqual来明确您的意图。如果您只需要它进行测试Equals,则不必覆盖它。AppointmentCollection如果应用程序本身需要它并且想要对其进行测试,请按list1.Equals(list2)字面意思编写测试以确保您自己的覆盖是测试的内容。

(当然,在任何情况下Appointment都需要覆盖。)

于 2013-09-05T09:56:44.990 回答