在F#中,我有一个包含几个字段的记录:
type myRecord = { a:float; b:float; c:float }
我正在使用FsCheck来测试一些使用此记录的属性。 对于(一个人为的)例子,
let verify_this_property (r:myRecord) = myFunction(r) = (r.a * r.b) / r.c
由于 myFunction 的内部实施限制,我想让FsCheck创建测试用例,其中每个字段a,b,c都限制为非负浮点数。
我怀疑这需要为 myRecord 创建一个生成器,但我无法找到任何如何执行此操作的示例。
任何人都可以提供指导吗?
答案 0 :(得分:7)
试试这个:
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
<!>
是中缀map
,对于应用风格非常有用。这是一个等效的生成器:
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
如果您不想全局注册您的生成器,可以使用forAll
:
Check.Quick (forAll Generators.arbMyRecord verify_this_property)
作为练习缩小;)
答案 1 :(得分:3)
您可以使用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)
虽然这会导致(基本上?)较慢的测试执行,因为FsCheck将不得不丢弃所有不合适的测试条目。