Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should one unit test the hashCode-equals contract?

In a nutshell, the hashCode contract, according to Java's object.hashCode():

  1. The hash code shouldn't change unless something affecting equals() changes
  2. equals() implies hash codes are ==

Let's assume interest primarily in immutable data objects - their information never changes after they're constructed, so #1 is assumed to hold. That leaves #2: the problem is simply one of confirming that equals implies hash code ==.

Obviously, we can't test every conceivable data object unless that set is trivially small. So, what is the best way to write a unit test that is likely to catch the common cases?

Since the instances of this class are immutable, there are limited ways to construct such an object; this unit test should cover all of them if possible. Off the top of my head, the entry points are the constructors, deserialization, and constructors of subclasses (which should be reducible to the constructor call problem).

[I'm going to try to answer my own question via research. Input from other StackOverflowers is a welcome safety mechanism to this process.]

[This could be applicable to other OO languages, so I'm adding that tag.]

like image 725
Paul Brinkley Avatar asked Oct 09 '08 17:10

Paul Brinkley


2 Answers

EqualsVerifier is a relatively new open source project and it does a very good job at testing the equals contract. It doesn't have the issues the EqualsTester from GSBase has. I would definitely recommend it.

like image 130
Benno Richters Avatar answered Sep 20 '22 13:09

Benno Richters


My advice would be to think of why/how this might ever not hold true, and then write some unit tests which target those situations.

For example, let's say you had a custom Set class. Two sets are equal if they contain the same elements, but it's possible for the underlying data structures of two equal sets to differ if those elements are stored in a different order. For example:

MySet s1 = new MySet( new String[]{"Hello", "World"} ); MySet s2 = new MySet( new String[]{"World", "Hello"} ); assertEquals(s1, s2); assertTrue( s1.hashCode()==s2.hashCode() ); 

In this case, the order of the elements in the sets might affect their hash, depending on the hashing algorithm you've implemented. So this is the kind of test I'd write, since it tests the case where I know it would be possible for some hashing algorithm to produce different results for two objects I've defined to be equal.

You should use a similar standard with your own custom class, whatever that is.

like image 22
Eli Courtwright Avatar answered Sep 21 '22 13:09

Eli Courtwright