Generating C# models in F# using FsCheck

2015-01-19

I’ve had some trouble getting FsCheck to work nicely with some types I have declared in C#. It seems to work perfectly fine if you have a type declared in F#, or an immutable C# class. But, we don’t all get to work with immutable classes. I wanted to be able to write a generator for a class that I didn’t own in C#, and then verify some properties using the NUnit plugin for FsCheck. After a bit of trial an error, I was able to come up with the following arrangement, which seems to work.

The Model

1
2
3
4
5
6
7
8
9
namespace Models
{
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public int Salary { get; set; }
}
}

The Generator

This module is defiened in it’s own file

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
module Generators
open FsCheck
open Models
let personGen =
gen {
let! n = Arb.generate<string>
let! a = Gen.choose(1,120)
let! s = Gen.choose(0, 100000)
return new Person(
Name = n,
Age = a,
Salary = s)
}
type PersonGenerator =
static member Valid() =
{ new Arbitrary<Person>() with
override x.Generator = personGen }

The Tests

The property tests can then be defined in a different .fs file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace FsCheckDemo
open NUnit.Framework
open FsCheck
open FsCheck.NUnit
open Models
[<TestFixture>]
type public Tests() =
[<TestFixtureSetUp>]
member t.SetUp() =
Arb.register<Generators.PersonGenerator>() |> ignore
[<Property>]
member x.``Person salary should not be the same as age``(p:Person) =
p.Salary <> p.Age

The reason for splitting the two chunks of F# code into two files, one in a module and one in a namespace, is mostly an issue of running the NUnit plugin. This was the only way I was able to get the Generator to register properly, and get the Property attribute to be picked up properly.

I’m still getting some issues with running the NUnit tests from ReSharper 9, but 8 works fine. As I go, I’m sure I’ll bump into some other issues. The intent is going to be performing some model based tests. Hopefully, now that I have a basic arrangement of what works, I’ll be able to add these new types of tests easily.