Unit test equality is not domain equality

By | June 11, 2013

I came across a question on stackoverflow concerning comparing object for equality in unit test. The poster basically wants to get rid of series of assertions like this:

I agree, this is ugly. The more so if you have multiple tests that assert on the equality of these properties. You can always factor it out into a helper function but you still end up actually writing the comparisons yourself.

The selected answer doesn’t feel right. The proposal is to implement Equals() in the class for your tested object. This is not always desirable or even possible. Consider the case where your use case actually makes use of Equals() in its logic. There may already exist an implementation of Equals() that satisfies different needs than those of your test. Moreover, when overriding Equals(), there is more to it than just this single function. GetHashCode() must be implemented too … and correctly ! If you don’t implement GetHashCode(), you may end up with subtle or not-so-subtle bugs if your object gets stored as a dictionary key. In most cases, it will not be an issue because only a very few classes are actually used a dictionary keys. However, if you get into the habit of overriding Equals() without GetHashCode(), you can be bitten hard !!

One of the most favored answer is to use reflection to discover the distinct properties. This is the way to go. Code that solely exists for testing purposes should be kept away from the classes you test. However, I find the proposed solution sub-optimal. For one thing, the method is solely dedicated to testing and directly calls Assert.AreEqual(). For another, I don’t like that it automatically recurse into IList properties, but this is a question of style.

I would propose a general purpose utility method like this.

and of course, the unit test that goes along with it:

It can then be used in a unit test like this:

You can wrap the method via a unit-test friendly static assert method or any way you like. The above test would fail in a quite explicit way. An error message looks like this:

What do you think ?

Leave a Reply