Compare Anything for Equality

Comparing objects for equality can be a pain in automated tests in C#. It works fine for primitive data types and even collections based on IEnumerable<T>, when you use NUnit's Assert-functions:

Assert.AreEqual (
  new[]{ 1, 2 },
  new[]{ 1, 2 }
);

But once you  enter the realm of custom data types, you're lost:

class PersonWithFields {
  public string Name;
  public DateTime DoB;
}

Assert.AreEqual(
  new PersonWithFields{ Name = "Peter", DoB = new DateTime (1987, 5, 12) },
  new PersonWithFields{ Name = "Peter", DoB = new DateTime (1987, 5, 12) }
); // will throw an exception

To make such a comparison work, you need to implement your own Equals() function and more.

That's fine, when you need that in your code anyway. But it's overkill to do it just for testing purposes.

However, in my experience, object comparisons in production code are far less frequent than in test code. That way, overriding Equals() etc. just makes testing harder – as much so that developers don't write automated tests at all.

That's bad, I'd say.

And switching to a language like F# which solves this problem by default is not an option for most.

The Equalidator to the rescue

But don't despair. Help is available from the Equalidator. It's a little library I wrote a couple of years back.

You can add the Equalidator package from NuGet. Or you can compile the tool yourself; it's hosted on GitHub.

With the Equalidator it's easy to check any two object graphs for equality. As a simple example comparison from above which did not work with NUnit:

equalidator.Equalidator.AreEqual (
  new PersonWithFields{ Name = "Peter", DoB = new DateTime (1987, 5, 12) },
  new PersonWithFields{ Name = "Peter", DoB = new DateTime (1987, 5, 12) }
);

But you can go deeper. Let's compare two trees:

class Node {
  public int Value;
  public IEnumerable<Node> Children;
}

var root1 = new Node{
  Value = 1,
  Children = new[]{
    new Node{Value = 11},
    new Node{
      Value = 12,
      Children = new List<Node>(){
        new Node{Value = 123}
      }
    }
  }
};

var root2 = new Node{ ... };

equalidator.Equalidator.AreEqual (root1, root2, true);

If the two object graphs are equal, i.e. contain the same values, then nothing happens. But if Equalidator finds a difference, it throws an exception.

Currently this exception is a bit broad brush, but still... the comparison is done dilligently and you know if the two graphs "look the same".

Equalidator comes with one switch only, currently at least. You can choose whether collections should be compared with strict type checking – and int[] then is never equal to a List<int> – or whether loose type checking should be used like this:

equalidator.Equalidator.AreEqual (
  new[] {1, 2, 3},
  new List<int>(new[] {1, 2, 3}),
  true
); // finds both collections to be equal

The default is false for the last parameter meaning strict type checking.

I hope this little tools makes it easier for you to write automated tests. So I hope you'll write more of them from now on ;-)

If you've any suggestions for Equalidator feel free to clone the repo, improve the code, and send me a pull request. (There is even some design documentation in the repo to make it a bit easier for you to find your way around in the code.)

This article was updated on 25.01.2021