Skip to content

Instantly share code, notes, and snippets.

@mathiasverraes
Last active September 11, 2015 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mathiasverraes/8b24dd16684f1981bd85 to your computer and use it in GitHub Desktop.
Save mathiasverraes/8b24dd16684f1981bd85 to your computer and use it in GitHub Desktop.
Testing fizzbuzz
-- in reaction to http://codemanship.co.uk/parlezuml/blog/?postid=1325
-- oneHundredIntegersSeparatedByCommas
-- integersDivisibleByThreeReplacedWithFizz
-- integersDivisibleByFiveReplacedWithBuzz
-- integersDivisibleByThreeAndFiveReplaedWithFizzBuzz
-- remainingNumbersAreUnchanged
-- Imho No amount of tests can explain fizzbuzz better than a declarative implementation:
fizz :: Int -> String
fizz n | n `mod` 15 == 0 = "FizzBuzz"
| n `mod` 3 == 0 = "Fizz"
| n `mod` 5 == 0 = "Buzz"
| otherwise = show n
-- My process for solving fizzbuzz might be:
-- TDD rule by rule to build up a solution
-- Refactor the solution to declarative style
-- Trash the tests
-- Add a single test with the purpose of illustrating the output of fizzbuzz to a reader, eg
-- assert(fizz 100 == ["1", "2", "Fizz" ...])

SUT for all x < n.

(Pseudocode)

testRegular ->
   assert(SUT[1] equals 1)
   assert(SUT[2] equals 2)
   assert(SUT[3] not equals 3)
   ...

testFizz ->
   assert(SUT[1] not contains "Fizz")
   assert(SUT[2] not contains "Fizz")
   assert(SUT[3] contains "Fizz")
   ...

testBuzz ->
   assert(SUT[1] not contains "Buzz")
   assert(SUT[2] not contains "Buzz")
   assert(SUT[3] not contains "Buzz")
   ...

Even though the above appears to test all the rules, it is not conclusive.

  • For n = 15, the output might be either FizzBuzz or BuzzFizz
  • We haven't tested for unwanted characters, eg SUT[3] == "FizzBlabla" would still pass

One solution is to add this:

testFizzBuzz ->
   assert(SUT[1] not equals "FizzBuzz")
   assert(SUT[2] not equals "FizzBuzz")
   ...
   assert(SUT[15] equals "FizzBuzz")
   ...

All of this amounts to highly verbose tests. More test code decreases readability and maintainabity, and therefore lowers the value of the test. My point is that, in the case of fizzbuzz, not to test the rules individually, but test the observable output of fizzbuzz, making no assumptions about the rules.

testFizzBuzz ->
	assert(SUT == ["1", "2", "Fizz", ...])

A oneliner that proves unequivocally the observable behaviour of fizzbuzz for x<n, surely is preferred to hundreds LoC that still allow wrong values to pass?

I'm not saying it is always better. Sometimes I test the behaviour as a whole, sometimes I test individual rules separately. This is a judgment call and should not be generalized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment