September 11, 2015

...Learn TDD with Codemanship

Tests Should Test One Thing (?)

The received wisdom - which chimes strongly with my own experience, and what I observe in teams - is that unit tests should have only one reason to fail.

There are several good reasons for this:

1. Small tests tend to be easier to pass, facilitating faster micro-iterations ("baby steps")

2. Small tests tend to be easier to understand, serving as clearer specifications

3. There tends to be less reasons for small tests to fail, making it easier to pinpoint the problem when it does

But, judging by discussions about an example in my previous blog post where I recommended not testing all the rules of FizzBuzz in a single test, some people disagree. Folk argue that single test like:

assertTrue(fizzBuzzer.fizzBuzz().startsWith("1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz")); more readable than several individual tests, each tackling speciic rules. Like:

assertEquals("1", fizzBuzzer.fizzBuzz().split(',')[0]);

There's a couple things to note in these exampes. Firstly, they are presented to require minimal context to understand. In reality, I would expect a good developer to refactor the test code to remove duplicate expressions for accessing individual elements in the FizzBuzz string. So tests might read more like:

assertEquals("1", fizzBuzzElementAtIndex(0));

I'd also expect the tests to be parameterised at some point, each test method named to document a specific FizzBuzz rule, like:

@Parameters({"3", "6"})
public void numbersDivisibleByThreeReplacedWithFizz(int index) {
assertEquals("Fizz", fizzBuzzElementAtIndex(index);

Someone looking to understand what FizzBuzz does - not how it works, but what it does - could simply read the test method names and see a list of the rules of FizzBuzz:

  • oneHundredIntegersSeparatedByCommas
  • integersDivisibleByThreeReplacedWithFizz
  • integersDivisibleByFiveReplacedWithBuzz
  • integersDivisibleByThreeAndFiveReplaedWithFizzBuzz
  • remainingNumbersAreUnchanged

  • I don't know about you, but I find that more readily accessible than oneHundredIntegersSeparatedByCommasWithAnyDivisibleByThreeReplacedWithFizzAndAnyDivisibleByFiveWithBuzzAndAnyDivisibleByThreeandFiveWithFizzBuzz, and more meaningful than the time-honoured cop-out: fizzBuzzStringShouldBeCorrect.

    What do you think?

    Posted 4 years, 10 months ago on September 11, 2015