问题
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?
回答1:
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 ;)
回答2:
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.
来源:https://stackoverflow.com/questions/8160421/in-fscheck-how-to-generate-a-test-record-with-non-negative-fields