5

在 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创建一个生成器,但我无法找到任何有关如何执行此操作的示例。

任何人都可以提供指导吗?

4

2 回答 2

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

The<!>是一个中缀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)

作为练习向左收缩;)

于 2011-11-23T04:07:30.180 回答
3

您可以避免使用FsCheck 条件属性创建自定义生成器

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 将不得不丢弃所有不合适的测试条目。

于 2011-11-17T11:01:58.303 回答