Erick Asto Oblitas
Erick Asto Oblitas

Reputation: 1409

Why the test 'Assert.AreEqual' has failed when I compare two empty list?

I have a class MyCustomClass:

public MyCustomClass
{
    public MyCustomClass()
    {
        MyObject = new List<MyCustomObject>();
    }

    public List<MyCustomObject> MyObject {get; set;}
}

In the Test:

List<MyCustomObject> aux = new List<MyCustomObject>();
MyCustomClass oClass = new MyCustomClass();
Assert.AreEqual(aux, oClass.MyObject)

The test has failed, why? Every property, static member, etc are the same.

Upvotes: 10

Views: 8498

Answers (3)

Stephen Swensen
Stephen Swensen

Reputation: 22297

I decompiled Assert.AreEqual (which is in the Microsoft.VisualStudio.QualityTools.UnitTestFramework GAC assembly) using dotPeek and found that Assert.AreEqual(aux, oClass.MyObject) will ultimately result in the following call where aux is expected and oClass.MyObject is actual:

object.Equals((object) expected, (object) actual)

From the documentation for the static object.Equals(Object, Object) we read:

The static Equals(Object, Object) method indicates whether two objects, objA and objB, are equal. It also enables you to test objects whose value is null for equality. It compares objA and objB for equality as follows:

It determines whether the two objects represent the same object reference. If they do, the method returns true. This test is equivalent to calling the ReferenceEquals method. In addition, if both objA and objB are null, the method returns true.

It determines whether either objA or objB is null. If so, it returns false.

If the two objects do not represent the same object reference and neither is null, it calls objA.Equals(objB) and returns the result. This means that if objA overrides the Object.Equals(Object) method, this override is called.

Now, List<T> is known to be a reference type, and we know that neither of the two lists you are comparing are null, so the final comparison between your two objects will be

expected.Equals(actual)

Since List<T> does not override Equals, it uses the base object implementation, which performs reference comparison, and thus fails (expected and actual were "newed" separately).

What you want is structural comparison, i.e. the pair-wise equality of the elements in your lists. See @ReedCopsey answer for the correct assertion for that (CollectionAssert.AreEqual).

Upvotes: 0

driis
driis

Reputation: 164291

As already answered, two lists of same type with zero elements are not considered equal.

The reason behind this, is that AreEqual actually calls aux.AreEqual(oClass.MyObject), using the objects own equality implementation. Because this is not overridden for List<T>, it falls back to the implementation in Object, which is a simple reference equality check. Those two lists are clearly not the same reference, and therefore, they are not considered equal.

Because the Equals method exists and is virtual on Object, your own classes can override Equals in order to provide another concept for equality than reference equality. This is done on objects like String, which compare equal even for different references, if the data is the same.

Upvotes: 4

Reed Copsey
Reed Copsey

Reputation: 564433

In this case Assert.AreEqual will check to see if the two objects are the same, and they're not. You should use CollectionAssert.AreEqual instead, which will return true if the two "have the same elements in the same order and quantity."

Upvotes: 19

Related Questions