В FsCheck, как создать тестовую запись с неотрицательными полями? - PullRequest
5 голосов
/ 17 ноября 2011

В 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 , но я не смог найти ни одного примера того, как это сделать.

Кто-нибудь может дать руководство?

Ответы [ 2 ]

7 голосов
/ 23 ноября 2011

Попробуйте это:

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)

Сокращение влево как упражнение;)

3 голосов
/ 17 ноября 2011

Вы можете избежать создания собственного генератора, используя условные свойства 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 придется отказаться от всехнеподходящие тестовые записи.

...