March 12, 2007 - A game of tenpins consists of ten frames

In my previous blog entry, I posted a set of acceptance tests for the first few stories. It's time to start writing the code to pass those tests. I prefer to discover the design through TDD rather than code directly to the customer-facing tests.

To get a feel for the requirements, I read the first rule:


//  2.1.1 A game of tenpins consists of ten frames. A player delivers two balls in each of the first
//  nine frames unless a strike is scored. In the tenth frame, a player delivers three balls if a
//  strike or spare is scored. Every frame must be completed by each player bowling in regular
//  order.

The first domain object mentioned in the rules is 'game' so I'll start with a test for a Game object.


public class GameTest {
  private Game game;

  @Before
  public void createGame() {
    game = new Game();
  }
}

At this point, I usually start bowling balls and calculating scores, but the first rule doesn't mention scores. It mentions frames. I'll go with the flow and see where it takes me.


  @Test
  public void shouldBeTenFramesWithTwoRollsInEach() {
    for(int frame = 0; frame < 10; frame++){
      game.bowl(3);
      game.bowl(4);
    }

    assertThat(game.isGameOver(), is(true));
  }

After a little Eclipse magic to create a Game class...


public class Game {
  public void bowl(int pins) {
  }

  public boolean isGameOver() {
    return false;
  }
}

...the tests fail. I can just change the return value of isGameOver() to make the test pass so I'll need another test to tease out the correct behavior of those methods.


  @Test
  public void theGameShouldNotBeOverAfterNineAndHalfFrames() {
    for(int frame = 0; frame < 9; frame++){
      game.bowl(3);
      game.bowl(4);
    }

    game.bowl(4);

    assertThat(game.isGameOver(), is(false));
  }

I make it pass by checking how many balls have been bowled:


  public void bowl(int pins) {
    ballCount++;
  }

  public boolean isGameOver() {
    return ballCount >= FRAMES_PER_GAME * PINS_PER_FRAME;
  }

All my unit tests pass and it looks like I've already done enough for the first story, so I'll run the acceptance tests and see if they pass.

The acceptance tests are abstract so I start by creating a concrete subclass:


public class SingleGameScoringTest extends SingleGameScoring {
  private Game game;

  @Before
  public void setUp() {
    game = new Game();
  }
}

The first thing I discover is that the Eclipse runner does not recognize a class as a JUnit4 test unless it has a method with the @Test annotation. In JUnit3, I often put my common tests in an abstract base class - looks like that won't work in JUnit4.

I need a workaround, so I'll add a test that a) forces me to adapt my implementation to the acceptance tests and b) forces the runner to find and run my tests.


  @Test
  public void hookUpAdaptorMethods() {
    deliverBall(0);
    assertThat(gameOver(), is(false));
    assertThat(numberOfFrames(), is(10));
  }

Those are all the methods I need to run the first set of tests and the implementation is straightforward:


  @Override
  protected void deliverBall(int pins) {
    game.bowl(pins);
  }

  @Override
  protected boolean gameOver() {
    return game.isGameOver();
  }

  @Override
  protected int numberOfFrames() {
    return Game.FRAMES_PER_GAME;
  }

I run them and they pass so the first story is complete. On to rule 2.1.2...


Posted by Kevin Lawrence at March 12, 2007 11:57 AM


Trackback Pings

TrackBack URL for this entry:


Comments

Post a comment




Remember Me?