Before so noble and so great a figure"
-- Shakespeare, Measure for Measure
Act I, Scene I, Lines 48-49
The Quest
One of the first things I asked myself while learning F# was, "This is great, how do I test this stuff?" I did what any programmer would do and asked the Google, which pointed me to a question on Stackoverflow and a slide deck on slideshare. Between the the top answer on Stackoverflow and the 5th slide in the deck. I was off and running doing TDD in F# with FsUnit and NCrunch!
Intro to FsUnit
FsUnit uses the BDD should style of testing, which I personally am starting to prefer. I hear, an example would be nice right about now; in the back of my head, here you go (these examples are taken from the FsUnit README.md):
1 |> should equal 1
1 |> should not' (equal 2)
"ships" |> should startWith "sh"
"ships" |> should not' (startWith "ss")
"ships" |> should endWith "ps"
"ships" |> should not' (endWith "ss")
[1] |> should contain 1
[] |> should not' (contain 1)
The pattern which FsUnit follows is:
{actual-result} |> should {statement-to-test} {expected-result}
Looking at the first line in the example (1 |> should equal 1) we have:
1 as the actual-result
equal as the statement-to-test
1 as the expected-result
F# is a functional language, so we should think of everything in the FsUnit test as a function. Given that, we see that the should is looking for: an actual-result, a statement-to-test (equal, not', endWith, contain, ...), and the expected-result. Using the |> pipe we get a readable form like, 1 should equal 1 (1 |> should equal ).
FsUnit with the Even or Odd example
Let us look at MSDN's favorite F# example, even or odd; using FsUnit?
Say we have the following:
let isOdd x =
if x % 2 = 0 then false
else true
let isEven x = isOdd x |> not
We can use the following to test these two functions using FsUnit and NUnit.
[<Test>]
let ``Given 2 isOdd is false`` () =
isOdd 2 |> should be False
[<Test>]
let ``Given 2 isEven is true`` () =
isEven 2 |> should be True
[<Test>]
let given_3_isOdd_is_true () =
isOdd 3 |> should equal true
[<Test>]
let given_3_isEven_is_false () =
isEven 3 |> should equal false
Looking at the tests we see that we can use backticks to allow for more readable names to our tests. For boolean results we can also choose between should be False and should equal false, the first using FsUnit's keyword be with its False and the other using equal and F#'s false. Both from my experience work the same, so it is more a question around readability and maintainability.
FsUnit FizzBuzz example
Using NUnit we can uses attributes like TestCase to pass in values to our FsUnit tests. Again the voice in the back of my head is saying, "How about an example?", so here it is for FizzBuzz:
open NUnit.Framework
open FsUnit
let (|DivisibleBy|_|) divisor n =
if n % divisor = 0 then Some() else None
let fizzbuzz n =
match n with
| DivisibleBy 3 & DivisibleBy 5 -> "FizzBuzz"
| DivisibleBy 3 -> "Fizz"
| DivisibleBy 5 -> "Buzz"
| _ -> string n
[<TestCase(2,"2")>]
[<TestCase(4,"4")>]
[<TestCase(3,"Fizz")>]
[<TestCase(9,"Fizz")>]
[<TestCase(5,"Buzz")>]
[<TestCase(25,"Buzz")>]
[<TestCase(15,"FizzBuzz")>]
[<TestCase(30,"FizzBuzz")>]
let ``Given this value the result is this`` (value, result) =
fizzbuzz value |> should equal result
Using a parameterized active pattern (based on yet another Stackoverflow response from Tomas Petricek!) we are able to have a FizzBuzz solution which does not test the mod 15 directly and is very expandable (in case the business wants a Woof for 7!).
We see that using the NUnit TestCase attribute we can simply have one FsUnit test which is passed in different input for the argument to fizzbuzz and the expected result!