- Replacing Reminders with Code
- Improving Readability
- Using a New Deck for Each Hand
- Gentlemen, Place Your Bets
- Wrapping Up
Improving Readability
Let’s modify the test for hand flow (see Listing 2).
Listing 2 Ensuring that a new deck is used for each hand.
public void testHandFlow() { addThreePlayers(); game.setButton(3); game.startHand(); Card[] deck1 = captureEntireDeck(); dealAllCardsInHand(); game.stopHand(); assertHandCompletion(1); game.startHand(); Card[] deck2 = captureEntireDeck(); dealAllCardsInHand(); game.stopHand(); assertHandCompletion(2); game.startHand(); Card[] deck3 = captureEntireDeck(); dealAllCardsInHand(); game.stopHand(); assertHandCompletion(3); assertFalse(areEqual(deck1, deck2, deck3)); }
Each time we revisit a test to modify its functionality is an opportunity to improve its expressiveness and minimize its redundancies. Three new test utility methods, captureEntireDeck, assertHandCompletion, and areEqual, help to improve testHandFlow’s readability. The first method, captureEntireDeck, is simple:
private Card[] captureEntireDeck() { return game.deck().top(Deck.SIZE); }
We use captureEntireDeck to store all cards from the deck used for each hand, since we’re going to need to ensure that each new hand uses a new deck.
We use assertHandCompletion to combine the otherwise repetitive assertion methods required after each hand is completed:
private void assertHandCompletion(int expectedButtonPosition) { assertEquals(expectedButtonPosition, game.buttonPosition()); assertNoCardsOut(); }
We use the final assertion in the test to demonstrate that all three hands were dealt using different decks. Here’s the utility method areEqual:
private boolean areEqual(Card[]... decks) { for (int i = 0; i < decks.length - 1; i++) if (!Arrays.equals(decks[i], decks[i + 1])) return false; return true; }
The new areEqual method is pretty generic! It’s also complex enough that it could use its own set of tests. While we technically don’t need to write tests against test code, it’s often a good idea. Sometimes abstracting, isolating, and testing test utilities helps programmers to recognize the usefulness of such utilities as reusable production classes.