Unit testing and objects equality
February 16th, 2009Let's assume that we have a class like below:
C#:
-
public class Foo : IEquatable<Foo>
-
{
-
private int variable;
-
-
public int Variable
-
{
-
get { return variable; }
-
set { variable = value; }
-
}
-
-
#region IEquatable<Foo> Members
-
-
public bool Equals(Foo other)
-
{
-
return this.variable == other.Variable;
-
}
-
-
#endregion
-
}
and a unit test for that:
C#:
-
[TestClass()]
-
public class FooTest
-
{
-
[TestMethod()]
-
public void EqualsTest()
-
{
-
one.Variable = 5;
-
two.Variable = 5;
-
-
Assert.AreEqual<Foo>(one, two, "AreEqual<Foo> failed");
-
Assert.AreEqual(one, two, "AreEqual failed");
-
Assert.AreSame(one, two, "AreSame failed");
-
}
-
}
and a question is - which Assert fails? All of them o_O
I could not find an explanation why implemented Equals method is not called. Framework always calls default Equals(object)

AreSame should not return true ever. Just use reflector and you will find it is implemented as follows:
if (!object.ReferenceEquals(expected, actual))
AreEqual – again if you use reflector you will see what is happening. Then you will probably write a test like this:
Foo one = new Foo();
one.Variable = 5;
Foo two = new Foo();
two.Variable = 5;
object objOne = one;
object objTwo = two;
Console.WriteLine(one.Equals(two));
Console.WriteLine(objOne.Equals(objTwo));
Here is the output:
True
False
This is “kinda” puzzling unless you go to msdn (http://msdn.microsoft.com/en-us/library/ms131190.aspx) and read:
Notes to Implementers:
If you implement Equals, you should also override the base class implementations of Object..::.Equals(Object) and GetHashCode so that their behavior is consistent with that of the IEquatable<(Of )>)..::.Equals method. If you do override Object..::.Equals(Object), your overridden implementation is also called in calls to the static Equals(System.Object, System.Object) method on your class. This ensures that all invocations of the Equals method return consistent results (…)
So you basically have a bug in your Foo class and your UnitTest found the bug – this is a damn good test
moozzyk
P.S. I hate details like this since they are showing how much I still don’t know. I also don’t think I would find this bug if I reviewed your code…
Thanks for a comprehensive comment. Yes, AreSame in this example is really stupid
Finally I had created an Assert exactly the same way like you proposed:
Assert.IsTrue(one.Equals(two));
Well, I don’t think the test needs to be fixed here – the test is good. It found a bug in your code. I think this is the code that needs to be fixed so that the result of both of the calls
(
Console.WriteLine(one.Equals(two));
Console.WriteLine(objOne.Equals(objTwo));
)
is the same. Otherwise it will hit you sooner or later (or I would say sooner than later)
moozzyk
I think you’re right
No remorse to the bad code!