14

When I have a Dictionary<string, int> actual and then create a completely new Dictionary<string, int> expected with the same values as actual.

  • Calling Assert.That(actual, Is.EqualTo(expected)); makes the test pass.

  • When using Assert.That(actual, Is.EquivalentTo(expected)); the test doesn't pass.

What is the difference between EqualTo() and EquivalentTo()?

Edit:

The message of the exception when the test doesn't pass is as follows:

Zoozle.Tests.Unit.PredictionTests.ReturnsDriversSelectedMoreThanOnceAndTheirPositions:
Expected: equivalent to < [Michael Schumacher, System.Collections.Generic.List`1[System.Int32]] >
But was:  < [Michael Schumacher, System.Collections.Generic.List`1[System.Int32]] >

My code looks like this:

[Test]
public void ReturnsDriversSelectedMoreThanOnceAndTheirPositions()
{
    //arrange
    Prediction prediction = new Prediction();

    Dictionary<string, List<int>> expected = new Dictionary<string, List<int>>()
    {
        { "Michael Schumacher", new List<int> { 1, 2 } }
    };

    //act
    var actual = prediction.CheckForDriversSelectedMoreThanOnce();

    //assert
    //Assert.That(actual, Is.EqualTo(expected));
    Assert.That(actual, Is.EquivalentTo(expected));
}

public Dictionary<string, List<int>> CheckForDriversSelectedMoreThanOnce()
{
    Dictionary<string, List<int>> expected = new Dictionary<string, List<int>>();
    expected.Add("Michael Schumacher", new List<int> { 1, 2 });

    return expected;
}
abatishchev
  • 98,240
  • 88
  • 296
  • 433
Garth Marenghi
  • 1,997
  • 5
  • 20
  • 38

2 Answers2

18

The question title forces me to state the following:

For enumerations, Is.EquivalentTo() does the comparison allowing any order of the elements. In contrast, Is.EqualTo() takes into account the exact order of the elements, like Enumerable.SequenceEqual() does.

However, in your case, there is no issue with ordering. The main point here is that Is.EqualTo() has extra code for dictionary comparison, as stated here.

Not so Is.EquivalentTo(). In your example, it will compare values of type KeyValuePair<string,List<int>> for equality, using object.Equals(). Since the dictionary values are of reference type List<int>, reference equality is used for comparing them.

If you modify your example such that the List {1, 2} is only instantiated once and used in both dictionaries, Is.EquivalentTo() will succeed.

tm1
  • 1,180
  • 12
  • 28
5

Both works for me:

var actual = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };
var expected = new Dictionary<string, int> { { "1", 1 }, { "2", 2 } };

Assert.That(actual, Is.EqualTo(expected)); // passed
Assert.That(actual, Is.EquivalentTo(expected)); // passed

  • Is.EqualTo() inside NUnit, if both objects are ICollection, uses CollectionsEqual(x,y) which iterates both to find the difference. I guess it's equal to Enumerable.SequenceEqual(x,y)

  • Is.EquivalentTo does this immediate because support sequences only: EquivalentTo(IEnumerable)

abatishchev
  • 98,240
  • 88
  • 296
  • 433
  • You are completely right, the problem with me is that in my dictionary I have a string as a key and another collection, a list, to hold integers as value. It's at that point that EquivalentTo throws an exception. – Garth Marenghi Jun 29 '11 at 09:08
  • @Garth: As you already pointed the reason in `List`. `CollectionsEqual` simultaneously iterates over both collections to compare, and because values are collections to, NUnit has no ability to compare it propeprly, and just calls `list1.Equals(list2)` which performs comparison by references, which fails. – abatishchev Jun 29 '11 at 09:24
  • This failing is for the `EquivalentTo()`, right? Because the `EqualTo()` seems to work just fine -> When I change a value in the list it picks it up just fine that something is not correct. – Garth Marenghi Jun 29 '11 at 09:50
  • @Garth: Yes, I was talking about `EquivalentTo()`. So use it for one-level-only collections, not for nested. – abatishchev Jun 29 '11 at 10:02