gpt4 book ai didi

f# - 如何使用 FsCheck 实现多参数生成?

转载 作者:行者123 更新时间:2023-12-01 10:34:01 25 4
gpt4 key购买 nike

如何使用 FsCheck 实现多参数生成?

我实现了以下内容以支持多参数生成:

// Setup
let pieces = Arb.generate<Piece> |> Gen.filter (isKing >> not)
|> Arb.fromGen

let positionsList = Arb.generate<Space list> |> Arb.fromGen

然后我使用这些参数来测试负责为给定检查器生成移动选项的函数的行为:
// Test
Prop.forAll pieces <| fun piece ->
Prop.forAll positionsList <| fun positionsItem ->

positionsItem |> optionsFor piece
|> List.length <= 2

在管理多个生成的参数类型时,嵌套 Prop.forAll 表达式是正确的技术吗?

是否有为被测函数生成多个参数的替代方法?

这是整个函数:
open FsCheck
open FsCheck.Xunit

[<Property(QuietOnSuccess = true)>]
let ``options for soldier can never exceed 2`` () =

// Setup
let pieces = Arb.generate<Piece> |> Gen.filter (isKing >> not)
|> Arb.fromGen

let positionsList = Arb.generate<Space list> |> Arb.fromGen

// Test
Prop.forAll pieces <| fun piece ->
Prop.forAll positionsList <| fun positionsItem ->

positionsItem |> optionsFor piece
|> List.length <= 2

更新

这是我的问题的解决方案,来自马克的回答:
[<Property(QuietOnSuccess = true, MaxTest=100)>]
let ``options for soldier can never exceed 2`` () =

// Setup
let pieceGen = Arb.generate<Piece> |> Gen.filter (isKing >> not)
let positionsGen = Arb.generate<Space list>

// Test
(pieceGen , positionsGen) ||> Gen.map2 (fun x y -> x,y)
|> Arb.fromGen
|> Prop.forAll <| fun (piece , positions) ->
positions |> optionsFor piece
|> List.length <= 2

最佳答案

作为一般观察,Arbitrary值很难组合,而 Gen值很容易。出于这个原因,我倾向于根据 Gen<'a> 来定义我的 FsCheck 构建块。而不是 Arbitrary<'a> .

Gen值,您可以使用 Gen.map2 组合多个参数, Gen.map3等,或者您可以使用 gen计算表达式。

Gen 积木

在 OP 示例中,而不是定义 piecespositionsListArbitrary ,将它们定义为 Gen值(value)观:

let genPieces = Arb.generate<Piece> |> Gen.filter (isKing >> not)

let genPositionsList = Arb.generate<Space list>

这些是类型的“构建块” Gen<Piece>Gen<Space list> , 分别。

请注意,我将它们命名为 genPieces而不是简单的 pieces , 等等。这可以防止以后发生名称冲突(见下文)。 (另外,我不确定在 pieces 中使用复数 s,因为 genPieces 只生成一个 Piece 值,但我因为我不知道你的整个域,我决定离开那个照原样。)

如果您只需要其中之一,您可以将其转换为 Arbitrary使用 Arb.fromGen .

如果需要组合它们,可以使用映射函数或计算表达式之一,如下所示。这会给你一个 Gen元组,然后您可以使用 Arb.fromGen将其转换为 Arbitrary .

使用 map2 撰写

如果您需要撰写 piecespositionsList进入参数列表,你可以使用 Gen.map2 :
Gen.map2 (fun x y -> x, y) genPieces genPositionList
|> Arb.fromGen
|> Prop.forAll <| fun (pieces, positionList) ->
// test goes here...
Gen.map2 (fun x y -> x, y)返回一个二元素元组(一对)值,您可以将其解构为 (pieces, positionList)在匿名函数中。

这个例子也应该说明为什么 genPiecesgenPositionListGen 更好的名字值:它们留有使用“裸”名称的空间 piecespositionList对于传递给测试主体的生成值。

使用计算表达式编写

对于更复杂的组合,我有时更喜欢的另一种选择是使用 gen计算表达式。

上面的例子也可以写成这样:
gen {
let! pieces = genPieces
let! positionList = genPositionList
return pieces, positionList }
|> Arb.fromGen
|> Prop.forAll <| fun (pieces, positionList) ->
// test goes here...

初始 gen表达式也返回一对,所以它等价于组合 Gen.map2 .

您可以使用您认为最易读的选项。

你可以看到更多非平凡的例子 Gen我文章中的组合 Roman numerals via property-based TDD .

关于f# - 如何使用 FsCheck 实现多参数生成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38839721/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com