Thursday, August 25, 2011

Minimalistic Unit Testsing in F#

So you want to do some unit testing in F#. Should you really use a framework?

The blessing and the curse of it is that there are so many frameworks out there that choosing one takes about as much time as creating one. Besides, what should a unit testing framework do anyway? There are frameworks offering real features such as randomized (QuickCheck) or exhaustive (SmallCheck) testing. On the other hand, frameworks like NUnit and xUnit do not seem to offer much - just bells and whistles such as result reporting and IDE integration. Is it worth it?

To roll our own, throw out everything but the bare bones. No reflection - all tests first class. No randomized / exhaustive testing - simple tests do not need that. Simply spend a few lines to define nice syntax, and start testing. Compile the test assembly to an executable, and run it on every build.

For example:

let mutable section = ""
let mutable status = 0
let mutable count = 0
exception Fail of string
let run (name: string) test =
try
test ()
count <- count + 1
with
| Fail reason ->
status <- 1
stderr.WriteLine("FAIL: {0}.{1} -- {2}", section, name, reason)
| e ->
status <- 1
stderr.WriteLine("FAIL: {0}.{1}", section, name)
stderr.WriteLine(e)
type Test(name: string) =
member this.Delay(f : unit -> unit) = run name f
member this.Zero() = ()
let Section name =
section <- name
let Throws<'T when 'T :> exn> f =
try
f ()
raise (Fail (sprintf "Does not throw: %O" typeof<'T>))
with
| :? 'T ->
()
let ( =? ) a b =
if a <> b then
raise (Fail (sprintf "Expected %A and got %A." a b))
let ( <>? ) a b =
if a = b then
raise (Fail (sprintf "Unexpected %A." a))
let runTests () =
Section "Arithmetic"
Test "addition" {
1 + 1 =? 2
1 + 0 =? 0
}
[<EntryPoint>]
let main args =
runTests ()
if status = 0 then
stdout.WriteLine("OK, {0} tests passed.", count)
status
view raw Test.fs hosted with ❤ by GitHub