MSTest:CollectionAssert.AreEquivalent失败。预期的集合包含1次出现

时间:2011-03-04 14:23:36

标签: c# .net unit-testing mstest

问题

任何人都可以告诉我为什么我的单元测试失败并出现此错误消息吗?

  

CollectionAssert.AreEquivalent失败。预期的集合包含1       发生的。实际上       集合包含0次出现。

目标

我想检查两个列表是否相同。如果它们包含具有相同属性值的相同元素,则它们是相同的。订单无关紧要。

代码示例

这是产生错误的代码。 list1list2相同,即彼此的复制粘贴。

[TestMethod]
public void TestListOfT()
{
    var list1 = new List<MyPerson>()
    {
        new MyPerson()
        {
            Name = "A",
            Age = 20
        },
        new MyPerson()
        {
            Name = "B",
            Age = 30
        }
    };
    var list2 = new List<MyPerson>()
    {
        new MyPerson()
        {
            Name = "A",
            Age = 20
        },
        new MyPerson()
        {
            Name = "B",
            Age = 30
        }
    };

    CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList());
}

public class MyPerson
{
    public string Name { get; set; }
    public int Age { get; set; }
}

我也试过这一行(source

CollectionAssert.AreEquivalent(list1.ToList(), list2.ToList());

和这一行(source

CollectionAssert.AreEquivalent(list1.ToArray(), list2.ToArray());

P.S。

相关的Stack Overflow问题:

我已经看到了这两个问题,但答案没有帮助。

5 个答案:

答案 0 :(得分:22)

你是对的。除非您提供类似IEqualityComparer<MyPerson>或实施MyPerson.Equals()的内容,否则两个MyPerson对象将与object.Equals进行比较,就像任何其他对象一样。由于对象不同,Assert将失败。

答案 1 :(得分:21)

如果我按MSDN所述添加IEqualityComparer<T>并使用Enumerable.SequenceEqual,则此功能正常。但请注意,现在元素的顺序是相关的。

在单元测试中

//CollectionAssert.AreEquivalent(list1, list2); // Does not work
Assert.IsTrue(list1.SequenceEqual(list2, new MyPersonEqualityComparer())); // Works

<强>的IEqualityComparer

public class MyPersonEqualityComparer : IEqualityComparer<MyPerson>
{
    public bool Equals(MyPerson x, MyPerson y)
    {
        if (object.ReferenceEquals(x, y)) return true;

        if (object.ReferenceEquals(x, null) || object.ReferenceEquals(y, null)) return false;

        return x.Name == y.Name && x.Age == y.Age;
    }

    public int GetHashCode(MyPerson obj)
    {
        if (object.ReferenceEquals(obj, null)) return 0;

        int hashCodeName = obj.Name == null ? 0 : obj.Name.GetHashCode();
        int hasCodeAge = obj.Age.GetHashCode();

        return hashCodeName ^ hasCodeAge;
    }
}

答案 2 :(得分:4)

在测试nHibernate持久化的集合时,我遇到了同样的错误。我能够通过覆盖 Equals和GetHashCode 方法来实现这一点。如果我没有覆盖两者,我仍然会遇到你提到的同样的错误:

CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s) of . 
The actual collection contains 0 occurrence(s).

我有以下对象:

public class EVProjectLedger
{
    public virtual long Id { get; protected set; }
    public virtual string ProjId { get; set; }
    public virtual string Ledger { get; set; }
    public virtual AccountRule AccountRule { get; set; }
    public virtual int AccountLength { get; set; }
    public virtual string AccountSubstrMethod { get; set; }

    private Iesi.Collections.Generic.ISet<Contract> myContracts = new HashedSet<Contract>();

    public virtual Iesi.Collections.Generic.ISet<Contract> Contracts
    {
        get { return myContracts; }
        set { myContracts = value; }
    }

    public override bool Equals(object obj)
    {
        EVProjectLedger evProjectLedger = (EVProjectLedger)obj;
        return ProjId == evProjectLedger.ProjId && Ledger == evProjectLedger.Ledger;
    }
    public override int GetHashCode()
    {
        return new { ProjId, Ledger }.GetHashCode();
    }
}

我使用以下方法测试过:

using (ITransaction tx = session.BeginTransaction())
{
    var evProject = session.Get<EVProject>("C0G");

    CollectionAssert.AreEquivalent(TestData._evProjectLedgers.ToList(), evProject.EVProjectLedgers.ToList());

    tx.Commit();
}

我正在使用nHibernate,它鼓励覆盖这些方法。我可以看到的一个缺点是我的Equals方法基于对象的业务键,因此使用业务键测试相等性而没有其他字段。您可以根据需要覆盖Equals,但要注意本文中提到的平等污染:

CollectionAssert.AreEquivalent failing... can't figure out why

答案 3 :(得分:0)

我写这个来测试订单不重要的集合:

    public static bool AreCollectionsEquivalent<T>(ICollection<T> collectionA, ICollection<T> collectionB, IEqualityComparer<T> comparer)
    {
        if (collectionA.Count != collectionB.Count)
            return false;

        foreach (var a in collectionA)
        {
            if (!collectionB.Any(b => comparer.Equals(a, b)))
                return false;
        }

        return true;
    }

不如使用SequenceEquals那么优雅,但它有效。

当然要使用它你只需:

Assert.IsTrue(AreCollectionsEquivalent<MyType>(collectionA, collectionB, comparer));

答案 4 :(得分:0)

如果您希望不必编写相等的比较器就可以实现这一目标,那么可以使用一个名为 FluentAssertions

的单元测试库。

https://fluentassertions.com/documentation/

它具有许多内置的相等性扩展功能,包括用于Collection的功能。您可以通过Nuget来安装它,它真的很容易使用。

以上述问题中的示例为基础,最后您必须写的是

list1.Should().BeEquivalentTo(list2);

默认情况下,顺序在两个集合中很重要,但是也可以更改。