Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MSTest: CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s) of

Question:

Can anyone tell me why my unit test is failing with this error message?

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

Goal:

I'd like to check if two lists are identical. They are identical if both contain the same elements with the same property values. The order is irrelevant.

Code example:

This is the code which produces the error. list1 and list2 are identical, i.e. a copy-paste of each other.

[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; }
}

I've also tried this line (source)

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

and this line (source)

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

P.S.

Related Stack Overflow questions:

I've seen both these questions, but the answers didn't help.

  • CollectionAssert use with generics?
  • Unit-testing IList with CollectionAssert
like image 941
Lernkurve Avatar asked Mar 04 '11 14:03

Lernkurve


2 Answers

You are absolutely right. Unless you provide something like an IEqualityComparer<MyPerson> or implement MyPerson.Equals(), the two MyPerson objects will be compared with object.Equals, just like any other object. Since the objects are different, the Assert will fail.

like image 154
neontapir Avatar answered Oct 22 '22 15:10

neontapir


It works if I add an IEqualityComparer<T> as described on MSDN and if I use Enumerable.SequenceEqual. Note however, that now the order of the elements is relevant.

In the unit test

//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;
    }
}
like image 25
Lernkurve Avatar answered Oct 22 '22 14:10

Lernkurve