Christoph Gockel

Shallow Tests with Spying

21 Oct 2014

This iteration was about improving the tests of my Java Tic Tac Toe.

After adding more substance to the tests I can say that looking back at the previous state of the tests, it feels like I tested nothing.

Sure, I verified that every part of the game interacts with one another as expected. But verifying real behaviour between the collaborators now definitely gives me more confidence that everything works.

Instead of just testing that a method has been called with a spy, verify the actual behaviour of the method you want to test. Take a look at the old revision of the tests for Game and you see that the highlighted test verifies that the method showNextPlayer() has been called.

@Test
public void announcesNextPlayerAsLongAsGameIsRunning() {
  playerOne.setNextMovesToPlay(1);
  game.nextRound();
  assertTrue(output.showNextPlayerHasBeenCalled);
}

So far so good, but I found a slightly better approach to that.

After a refactoring, this test still uses a test double, but it verifies that showNextPlayer() is called correctly from within Game.

@Test
public void announcesNextPlayerAsLongAsGameIsRunning() {
  playerOne.setNextMovesToPlay(1);
  game.nextRound();
  assertEquals(playerOne.getMark(), output.announcedPlayer);
}

Another thing I noticed quite often was that I could replace two tests that verified spies, with one test that verifies behaviour.

This is visible in the tests for HumanPlayer. There were two tests that made sure it called the correct methods on its Input object as well as the Board that is passed.

@Test
public void getsItsNextMoveFromItsInput() {
  player.nextMove(board);

  assertTrue(input.getMoveHasBeenCalled);
}

@Test
public void placesItsMoveOnTheBoard() {
  input.move = 2;

  player.nextMove(board);

  assertTrue(board.setMoveHasBeenCalled);
  assertEquals(2, board.lastMove);
}

These two tests were really just verifying that the player made a move on the board. This has been refactored so that the outcome of the interaction between the HumanPlayer and its collaborators is verified.

@Test
public void placesItsMoveOnTheBoard() {
  input.move = 2;

  Board newBoard = player.nextMove(board);

  assertEquals(player.getMark(), nthMarkOnBoard(2, newBoard));
}

The next time I need to use spies to verify something, I will definitely think twice.