First, a Game class. Maybe I should call it YatzyGame. Nah, I’ll stick with Game. Wooohooo prttoooo, Hold it, hold it … Of course I mean I should test the behaviour of a game.

So what is the behavior of a YatzyGame. Well, for starters, the score for a player in a newly created game should be equal to zero. It could be that a game could end up with a zero score as well. That is a another case thou.

 

public class GameBehaviour extends RMockTestCase {
	public void testShouldComputeScorePerPlayer() throws Exception {
		Game game = new Game();
		game.addRoll("Player", new int [] {1, 2, 3, 4, 5});
		assertThat(game.score("Player"), is.eq(15));
	}
}

I decided to use RMockTestCase because of the assertThat-syntax. I’m really fond of that. Other than that this is not very different from a regular ‘test’.

Apart from the name of the TestCase and the fact that the test method isn’t exactly testing one method, it’s testing *drumroll* behavior. It looks like regular TDD. It’s an important difference thou.

Well, off to the implementation. Clickety clack … a few moments, a few ctrl-1 and ctrl-spaces later:



public class Game {

	public void addRoll(String playerName, int[] roll) {
		throw new UnsupportedOperationException();
	}

	public Object score(String playerName) {
		throw new UnsupportedOperationException();
	}

}

This won’t run. But the rule is red-green-refactor. Notice the UnsupportedOperationException(). It’s a rather neat default behavior I’ve added to my eclipse code templates. Better than the pesky return 0 or return null for that matter.

Off to the TestCase. Ctrl-F6, Alt-Shift-X + T. Red bar.

As I suspected. UnsupportedOperationException.


public class Game {

	public void addRoll(String playerName, int[] roll) {
	}

	public int score(String playerName) {
		return 15;
	}
}

Some quick changes, Ctrl-F11, it’s green. Refactoring, nah, not needed at this point. Time for some more behavior. Maybe the possibility to add more that one roll. Yeah, that’s what I want. At least for now.

Adding this:


public void testShouldComputeAllRollsForAGivenplayer() throws Exception {
	Game game = new Game();
	game.addRoll("Player", new int [] {1, 2, 3, 4, 5});
	game.addRoll("Player", new int [] {1, 1, 1, 1, 1});

	assertThat(game.score("Player"), is.eq(20));
}

Some duplication in the tests noted. I’ll remove it when tests turn to green. Ctrl-F11, RED. Thank you! Off to the implementation.


public class Game {

	private List<int[]> scores;

	public void addRoll(String playerName, int[] roll) {
		scores.add(roll);
	}

	public int score(String playerName) {
		int score = 0;
		for (int[] roll : scores) {
			for (int i = 0; i < roll.length; i++) {
				score += roll[i];
			}
		}
		return score;
	}
}

Yeah, that’s it. Ctrl-F11. Huh. NullPointer. Oh. scores aren’t initialized properly. Changing line 8 to this, should do the trick:

private List scores = new ArrayList();

Ctrl-F11, yeah, it did. If this would’ve taken more that 60 seconds to locate I might have considered swiping the implementation and restarted. Or undoed until the last ‘green moment’. Ok, it’s green. Refactor time.


public class GameBehaviour extends RMockTestCase {

	private Game game;
	private int[] straightRoll;

	protected void setUp() throws Exception {
		game = new Game();
		straightRoll = new int[] { 1, 2, 3, 4, 5 };
		game.addRoll("Player", straightRoll);
	}

	public void testShouldComputeScorePerPlayer() throws Exception {
		assertThat(game.score("Player"), is.eq(15));
	}

	public void testShouldComputeAllRollsForAGivenplayer() throws Exception {
		int[] yatzyRoll = new int[] { 1, 1, 1, 1, 1 };
		game.addRoll("Player", yatzyRoll);
		assertThat(game.score("Player"), is.eq(20));
	}
}

Ctrl-F11, still green. That’s good.

Knowing my way in the Yatzy game i noticed a Straight and a Yatzy. Although I intentionally picked these number it’s pretty good practice naming your variables correctly. It will probably help me later on. I also moved a few things to the fixture (setUp).

What might be the next move. I now notice the testShouldComputeScorePerPlayer doesn’t even verify that it computes per player. I bet this wouldn’t have happened if I had a PP-partner. This has to be taken care of before I take on anything else. It’s pretty boring to play Yatzy by yourself really. But it’s even more so playing against someone who is constantly getting the same score as yourself.

Adding another row to the testShouldComputeScorePerPlayer should make the bar red.


public void testShouldComputeScorePerPlayer() throws Exception {
	assertThat(game.score("Player"), is.eq(15));
	assertThat(game.score("AnotherPlayer"), is.eq(0));
}

Ctrl-F11, yeah. It did. Ctrl-F6 and start implementing. Five minutes later I come up with this.


public class Game {

	private Map<String, List<int[]>> playerScores = new HashMap<String, List<int[]>>();

	public void addRoll(String playerName, int[] roll) {
		List<int[]> scores = new ArrayList<int[]>();
		scores.add(roll);

		playerScores.put(playerName, scores);
	}

	public int score(String playerName) {
		int score = 0;
		List<int[]> scores = new ArrayList<int[]>();
		if (playerScores.containsKey(playerName)) {
			scores = playerScores.get(playerName);
		}

		for (int[] roll : scores) {
			for (int i = 0; i < roll.length; i++) {
				score += roll[i];
			}
		}
		return score;
	}
}

Guess what. This breaks another test. Namely testShouldComputeAllRollsForAGivenplayer: “<5> does not pass the constraint <eq(<20>)>”. I Wonder why.

Looking at the test case it seems like it’s not summing up the scores of the rolls. I can see the guilty code in front of me now. Laughing at my blank face already. Fixing it reveals, or rather adds some duplication making the code look like this.


public class Game {

	private Map<String, List<int[]>> playerScores = new HashMap<String, List<int[]>>();

	public void addRoll(String playerName, int[] roll) {

		List<int[]> scores = new ArrayList<int[]>();
		if (playerScores.containsKey(playerName)) {
			scores = playerScores.get(playerName);
		}

		scores.add(roll);
		playerScores.put(playerName, scores);
	}

	public int score(String playerName) {
		int score = 0;

		List<int[]> scores = new ArrayList<int[]>();
		if (playerScores.containsKey(playerName)) {
			scores = playerScores.get(playerName);
		}

		for (int[] roll : scores) {
			for (int i = 0; i < roll.length; i++) {
				score += roll[i];
			}
		}
		return score;
	}
} 

This is great. Green bar and time to refactor. Some renaming of variables and one extract method made the code a bit better. Check out the code below. I think I will call this a day.


public class Game {

	private Map<String, List<int[]>> playerScores = new HashMap<String, List<int[]>>();

	public void addRoll(String playerName, int[] roll) {
		List<int[]> rolls = getScoreForPlayer(playerName);

		rolls.add(roll);
		playerScores.put(playerName, rolls);
	}

	public int score(String playerName) {
		List<int[]> rolls = getScoreForPlayer(playerName);

		int score = 0;
		for (int[] roll : rolls) {
			for (int i = 0; i < roll.length; i++) {
				score += roll[i];
			}
		}
		return score;
	}

	private List<int[]> getScoreForPlayer(String playerName) {
		List<int[]> rolls = new ArrayList<int[]>();
		if (playerScores.containsKey(playerName)) {
			rolls = playerScores.get(playerName);
		}
		return rolls;
	}
}
Advertisements

About Ola Ellnestam

Agile Coach, Systems developer, Agile Practitioner and father of three.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s