red-green starts with red

Suppose I've written a test and got it passing...
@Test
public void yahtzee_full_house_scores_25() {
  assertEquals(25, 
    new YahtzeeScorer(4,4,3,4,3).fullHouse());
}
After refactoring I write my next test...
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
And this passes first time. That is, it passes without failing first. One of the reasons for failing first is to be sure the test is actually running. For example, suppose I'd forgetten to write @Test and didn't notice that the JUnit output wasn't showing one more test passing. Ooops. A question I've been asked on several occasions is whether, in this situation, you should change the code or the tests to force an initial red. For example, my first version of the yahtzee_not_full_house_scores_0 could have been this, (where I've deliberately used 42 instead of 0 simply because 42 is a good example of a number that is not 0):
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(42, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
I see it fail, and then change the 42 to 0 and see it pass. This works, and I have done this. Perhaps you have too. If so, do you agree that it doesn't feel right? I've learned that when something doesn't feel right my subconscious is trying to tell me something. I've learned that when I've got two choices it's often a good idea to look for a third. And there is a third way. I could instead start with this:
@Test
public void yahtzee_not_full_house_scores_0() {
  fail("RED-FIRST");
}
And when I've seen it fail, I delete the fail() and write the actual code I want to write:
@Test
public void yahtzee_not_full_house_scores_0() {
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
Or, as an alternative, I could start with this:
@Test
public void yahtzee_not_full_house_scores_0() {
  fail("RED-FIRST");
  assertEquals(0, 
    new YahtzeeScorer(4,4,4,4,4).fullHouse());
}
and when I've seen it fail I simply delete the fail() line.

Either way I get the mechanics of seeing the fail out of the way and then I write the code as a separate thing. By un-asking the question I avoid having to decide what to temporarily fiddle with - the code or the tests. I get to write the code I actually want to write. All the time.

No comments:

Post a Comment