The Importance of Overridding Equals

I'm trying to write JUnit tests for some code that uses classes defined in Netscape's Lightweight Directory Access Protocol (LDAP) Software Development Kit (SDK) and I am having difficulties because the authors of several classes did not override equals.

For example, suppose I want to write a JUnit test for a method that returns an LDAPModificationSet. My first attempt is as follows:

public void testGetModifications()
{
  final LDAPModificationSet expected = // some expected modifications
  final LDAPModificationSet actual = classUnderTest.methodUnderTest();
  assertEquals(expected, actual);
}

No matter how hard I try, this test will always fail. LDAPModificationSet does not override equals, so its equals method only returns true when passed the exact same instance.

Consider the alternatives for my test:

  • Assert something weaker. For example, instead of assertEquals(expected, actual), I could use assertEquals(expected.size(), actual.size()).
  • Write my own method that compares LDAPModificationSet instances. For example, I could create an LdapModificationSets class with a method boolean equals(LDAPModificationSet firstSet, LDAPModificationSet secondSet).
  • Have my test manually compare each element in LDAPModificationSet. (Although that's not even possible in this case, because each element is an LDAPModification, and that class also doesn't override equals.)

None of these alternatives are particularly fun.

The moral of this story: Override equals in value objects! The second moral of this story - buy "Effective Java: Second Edition" because Joshua Bloch already made this point in Item 8 when he wrote the book!