Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JUnit theory for hashCode/equals contract

Tags:

The following class serve as generic tester for equals/hashCode contract. It is a part of a home grown testing framework.

  • What do you think about?
  • How can I (strong) test this class?
  • It is a good use of Junit theories?

The class:

@Ignore @RunWith(Theories.class) public abstract class ObjectTest {      // For any non-null reference value x, x.equals(x) should return true     @Theory     public void equalsIsReflexive(Object x) {         assumeThat(x, is(not(equalTo(null))));         assertThat(x.equals(x), is(true));     }      // For any non-null reference values x and y, x.equals(y)      // should return true if and only if y.equals(x) returns true.     @Theory     public void equalsIsSymmetric(Object x, Object y) {         assumeThat(x, is(not(equalTo(null))));         assumeThat(y, is(not(equalTo(null))));         assumeThat(y.equals(x), is(true));         assertThat(x.equals(y), is(true));     }      // For any non-null reference values x, y, and z, if x.equals(y)     // returns true and y.equals(z) returns true, then x.equals(z)      // should return true.     @Theory     public void equalsIsTransitive(Object x, Object y, Object z) {         assumeThat(x, is(not(equalTo(null))));         assumeThat(y, is(not(equalTo(null))));         assumeThat(z, is(not(equalTo(null))));         assumeThat(x.equals(y) && y.equals(z), is(true));         assertThat(z.equals(x), is(true));     }      // For any non-null reference values x and y, multiple invocations     // of x.equals(y) consistently return true  or consistently return     // false, provided no information used in equals comparisons on     // the objects is modified.     @Theory     public void equalsIsConsistent(Object x, Object y) {         assumeThat(x, is(not(equalTo(null))));         boolean alwaysTheSame = x.equals(y);          for (int i = 0; i < 30; i++) {             assertThat(x.equals(y), is(alwaysTheSame));         }     }      // For any non-null reference value x, x.equals(null) should     // return false.     @Theory     public void equalsReturnFalseOnNull(Object x) {         assumeThat(x, is(not(equalTo(null))));         assertThat(x.equals(null), is(false));     }      // Whenever it is invoked on the same object more than once      // the hashCode() method must consistently return the same      // integer.     @Theory     public void hashCodeIsSelfConsistent(Object x) {         assumeThat(x, is(not(equalTo(null))));         int alwaysTheSame = x.hashCode();          for (int i = 0; i < 30; i++) {             assertThat(x.hashCode(), is(alwaysTheSame));         }     }      // If two objects are equal according to the equals(Object) method,     // then calling the hashCode method on each of the two objects     // must produce the same integer result.     @Theory     public void hashCodeIsConsistentWithEquals(Object x, Object y) {         assumeThat(x, is(not(equalTo(null))));         assumeThat(x.equals(y), is(true));         assertThat(x.hashCode(), is(equalTo(y.hashCode())));     }      // Test that x.equals(y) where x and y are the same datapoint      // instance works. User must provide datapoints that are not equal.     @Theory     public void equalsWorks(Object x, Object y) {         assumeThat(x, is(not(equalTo(null))));         assumeThat(x == y, is(true));         assertThat(x.equals(y), is(true));     }      // Test that x.equals(y) where x and y are the same datapoint instance     // works. User must provide datapoints that are not equal.     @Theory     public void notEqualsWorks(Object x, Object y) {         assumeThat(x, is(not(equalTo(null))));         assumeThat(x != y, is(true));         assertThat(x.equals(y), is(false));     } } 

usage:

import org.junit.experimental.theories.DataPoint;  public class ObjectTestTest extends ObjectTest {      @DataPoint     public static String a = "a";     @DataPoint     public static String b = "b";     @DataPoint     public static String nullString = null;     @DataPoint     public static String emptyString = ""; } 
like image 667
dfa Avatar asked May 07 '09 23:05

dfa


People also ask

What is the contract between hashCode and equals?

The Contract Between equals() and hashcode() If two objects are equal according to the equals(Object) method, then calling the hashcode() method on each of the two objects must produce the same integer result.

What is the importance of the hashCode () and equals () contract?

If two objects are equal(according to equals() method) then the hashCode() method should return the same integer value for both the objects. But, it is not necessary that the hashCode() method will return the distinct result for the objects that are not equal (according to equals() method).

What is the hashCode () and equals () function?

Java hashCode() An object hash code value can change in multiple executions of the same application. If two objects are equal according to equals() method, then their hash code must be same. If two objects are unequal according to equals() method, their hash code are not required to be different.

How we implement hashCode and equals method in Java?

hashCode() method This method must be overridden in every class which overrides equals() method. Syntax : public int hashCode() // This method returns the hash code value // for the object on which this method is invoked.


2 Answers

One thing to consider: testing an object's conformance to the equals contract should involve instances of other types. In particular, problems are likely to appear with instances of a subclass or superclass. Joshua Bloch gives an excellent explanation of the related pitfalls in Effective Java (I'm reusing duffymo's link, so he should get credit for it) -- see the section under Transitivity involving the Point and ColorPoint classes.

True, your implementation doesn't prevent someone from writing a test that involves instances of a subclass, but because ObjectTest is a generic class it gives the impression that all data points should come from a single class (the class being tested). It might be better to remove the type parameter altogether. Just food for thought.

like image 141
Bobby Eickhoff Avatar answered Oct 27 '22 20:10

Bobby Eickhoff


Joshua Bloch lays out the contract for hash code and equals in chapter 3 of "Effective Java". Looks like you covered a great deal of it. Check the document to see if I missed anything.

like image 29
duffymo Avatar answered Oct 27 '22 21:10

duffymo