The Contract for Equality


The Java API documentation for the equals method in Object provides a list of what defines an equivalence relation between two objects:

Reflexivity:

x.equals(x)

Symmetry:

x.equals(y) if-and-only-if (iff) y.equals(x)

Transitivity:

if x.equals(y) and y.equals(z), then x.equals(z)

Consistency:

x.equals(y) returns a consistent value given consistent state

Comparison to null:

!x.equals(null)


The above contract should hold true for all non-null values of x and y. You can implement each of these rules in your unit test for equality.[6]

[6] A nice set of JUnit extensions, located at http://sourceforge.net/projects/junit-addons, provides an automated means of testing the equality contract.

 public void testEquality() {    Course courseA = new Course("NURS", "201");    Course courseAPrime = new Course("NURS", "201");    assertEquals(courseA, courseAPrime);    Course courseB = new Course("ARTH", "330");    assertFalse(courseA.equals(courseB));    // reflexivity    assertEquals(courseA, courseA);    // transitivity    Course courseAPrime2 = new Course("NURS", "201");    assertEquals(courseAPrime, courseAPrime2);    assertEquals(courseA, courseAPrime2);    // symmetry    assertEquals(courseAPrime, courseA);    // consistency    assertEquals(courseA, courseAPrime);    // comparison to null    assertFalse(courseA.equals(null)); } 

When you run your tests, everything will pass but the final assertion in testEquality. You will receive a NullPointerException: The that argument is null and the equals code attempts to access its fields (department and object). You can add a guard clause to return false if the argument is null:

 @Override public boolean equals(Object object) {    if (object == null)       return false;    Course that = (Course)object;    return       this.department.equals(that.department) &&       this.number.equals(that.number); } 

You might choose to represent each of the "qualities of equality" (reflexivity, transitivity, symmetry, consistency, and comparison to null) in a separate test. There are differing views on approaches to TDD. Some developers feel that you should structure your code so that each test contains a single assertion.[7] I take the viewpoint that the goal of a test is to prove a single piece of functionality. Doing so may require many assertions/postconditions. In this example, the many assertions you just coded represent a complete contract for a single piece of functionalityequality.

[7] [Astels2004].



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net