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:

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].

Apples and Oranges

Since the equals method takes an Object as parameter, you can pass anything to it (and the code will still compile). Your equals method should handle this situation:

// apples & oranges
assertFalse(courseA.equals("CMSC-120"));

Even though the String value matches the department and number of courseA, a Course is not a String. You would expect this comparison to return false. When Java executes the equals method, however, you receive a ClassCastException. The line of the equals method that executes the cast is the cause:

You learned about the getClass method in Lesson 8. It returns a class constant. For the example comparison that threw the ClassCastException, the class constant of the receiver is Course.class, and the class constant of the parameter is String.class. Class constants are uniquethere is only one "instance" of the Class object Course.class. This uniqueness allows you to compare class constants using the operator != (not equal to) instead of comparing them using equals.

Some developers choose to use the instanceof operator. The instanceof operator returns true if an object is an instance of, or subclass of, the target class. Here is the equals method rewritten to use instanceof.

You should initially prefer to compare the classes of the receiver and argument, instead of using instanceof. The class comparison only returns true if both objects are of the exact same type. Introduce instanceof later if you need to compare objects irrespective of their position in an inheritance hierarchy. See Lesson 12 for more information on instanceof.

JUnit and Equality

Sometimes I will code equals tests to be a bit more explicit. Instead of saying:

assertEquals(courseA, courseB);

I'll express the comparison as:

assertTrue(courseA.equals(courseB));

You should be clear on the fact that assertEquals uses the equals method for reference comparisons. But it can be helpful to explicitly emphasize that fact, and show that the equals method is what you're actually testing.

You may want to compare two references to see if they are the same. In other words, do they point to the same object in memory? You could code this comparison as:

assertTrue(courseA == courseB);

or as:

assertSame(courseA, courseB);

You should prefer the second assertion form, since it supplies a better error message upon failure. As before, though, you might choose to explicitly show the == comparison if for purposes of building an equals method test.