In F#, I have a record with a few fields:
type myRecord = { a:float; b:float; c:float }
I am using FsCheck to test some properties which use this record. For (a contrived) example,
let verify_this_property (r:myRecord) = myFunction(r) = (r.a * r.b) / r.c
Due to the internal implementation restrictions of myFunction, I would like to have FsCheck create test cases in which each of the fields a,b,c are restricted to non-negative floats.
I suspect this requires creating a generator for myRecord, but I have not been able to find any examples of how to do this.
Can anyone supply guidance?
Try this:
type Generators =
static member arbMyRecord =
fun (a,b,c) -> { myRecord.a = a; b = b; c = c }
<!> (Arb.generate<float> |> Gen.suchThat ((<) 0.) |> Gen.three)
|> Arb.fromGen
Arb.register<Generators>() |> ignore
Check.Quick verify_this_property
The <!>
is an infix map
, useful for applicative style. This is an equivalent generator:
type Generators =
static member arbMyRecord =
Arb.generate<float>
|> Gen.suchThat ((<) 0.)
|> Gen.three
|> Gen.map (fun (a,b,c) -> { myRecord.a = a; b = b; c = c })
|> Arb.fromGen
If you don't want to globally register your generator, you can use forAll
:
Check.Quick (forAll Generators.arbMyRecord verify_this_property)
Shrinking left as an exercise ;)
You can avoid creating custom generator by using FsCheck conditional properties
let verify_this_property (r:myRecord) =
(r.a > 0.0 && r.b > 0.0 && r.c > 0.0) ==> lazy (myFunction r = (r.a * r.b) * r.c)
Though this will result in (substantially?) slower execution of the test since FsCheck will have to discard all unsuitable test entries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With