Crafting Java with Test-Driven Development, Part 3: Testing Hash Codes
- Developing Hash Codes
- Hash Tables
- More Contracts
- The setUp Method
- Completing the Contract
- Why Bother?
Developing Hash Codes
Adding tests and code for equality in the Card class in part 2 of this series allowed us to simplify the code written for our Deck creation test. The test method, testCreate, is easy to read (see Listing 1) and succinctly describes the state for a new Deck.
Listing 1 testCreate method in DeckTest.
public void testCreate() { Deck deck = new Deck(); assertEquals(Deck.SIZE, deck.cardsRemaining()); for (Suit suit: Suit.values()) for (Rank rank: Rank.values()) assertTrue(deck.contains(rank, suit)); }
Currently, the Deck stores all of the cards in an ArrayList assigned to a List reference:
private List<Card> cards = new ArrayList<Card>();
Suppose we want to store the cards in a set instead of a list data structure. As an exercise, change this declaration and initialization to the following:
private Set<Card> cards = new HashSet<Card>();
The nice thing about the current design is that we’re free to make this change, because no client code depends on the internal representation of a deck. However, rerunning your tests shows that the tests break! You should receive an assertion failure that’s triggered by this line of code in DeckTest:
assertTrue(deck.contains(rank, suit));
The problem is that under the covers, HashSet uses the hash code of a card to determine where it’s stored.