Thursday, September 24, 2009

FsCheck xUnit integration

I am using xUnit.net at work on an F# project. I wanted to incorporate FsCheck and check properties via xUnit.net, but there is no built-in integration. I tried this from Matthew Podwysocki, but it is out of date with respect to the versions I am using (xUnit.net 1.5, FsCheck 0.6.1).

EDIT 28/09/2009: Here is the new and improved version based on Kurt's comment.

module FsCheckXunit

open FsCheck
open FsCheck.Runner
open Xunit

let xUnitRunner =
{ new IRunner with
member x.OnArguments(_,_,_) = ()
member x.OnShrink(_,_) = ()
member x.OnFinished(name, result) =
match result with
| True data -> Assert.True(true)
| _ -> Assert.True(false, testFinishedToString name result)
}

let config = {quick with Runner = xUnitRunner}

Below is the first version I adapted from Matthew's post and the FsCheck source code.
module FsCheckXunit

open FsCheck
open FsCheck.Runner
open Xunit

let xUnitRunner =
{ new IRunner with
member x.OnArguments(_,_,_) = ()
member x.OnShrink(_,_) = ()
member x.OnFinished(name, result) =
match result with
| True data ->
Assert.True(true)
data.Stamps |> Seq.iter (fun x -> printfn "%d - %A" (fst x) (snd x))
| False (data,_,args,Exception e,_) ->
Assert.True(false, sprintf "%s - Falsifiable after %i tests (%i shrinks): %A with exception %O"
name data.NumberOfTests data.NumberOfShrinks args e)
| False (data,_,args,Timeout i,_) ->
Assert.True(false, sprintf "%s - Timeout of %i milliseconds exceeded after %i tests (%i shrinks): %A"
name i data.NumberOfTests data.NumberOfShrinks args)
| False (data,_,args,_,_) ->
Assert.True(false, sprintf "%s - Falsifiable after %i tests (%i shrinks): %A"
name data.NumberOfTests data.NumberOfShrinks args)
| Exhausted data -> Assert.True(false, sprintf "Exhausted after %d tests" (data.NumberOfTests) )
}

let config = {quick with Runner = xUnitRunner}

2 comments:

Kurt Schelfthout said...

Hi,

This code could be simpler: there is a function 'testFinishedToString' which takes the name and the testResult in the OnFinished, and produces the standard FsCheck output string (including labels,... and anything that might be added in the future). Then you only need to pattern match to determine the outcome of the xUnit test, passing in the generated string.

Kurt

Brad Clow said...

Thanks Kurt. I have updated my post.