gpt4 book ai didi

f# - 如何在 FsCheck 中生成 "complex"对象?

转载 作者:行者123 更新时间:2023-12-04 02:09:53 24 4
gpt4 key购买 nike

我想创建一个 FsCheck Generator生成“复杂”对象的实例。所谓复杂,是指 C# 中的现有类,它具有许多子属性和集合。这些属性和集合又需要为它们生成数据。

想象一下这个类被命名为 Menu与子收藏 DishesDrinks (我正在编造这个,所以忽略糟糕的设计)。我想做以下事情:

  • 生成变量号Dishes和可变数量Drinks .
  • 生成DishDrink使用 FsCheck API 填充其属性的实例。
  • Menu 上设置一些其他原始属性使用 FsCheck API 的实例。

  • 如何为这种类型的实例编写生成器?这是一个坏主意吗? (我是基于属性的测试的新手)。我已经阅读了文档,但到目前为止显然还没有将其内化。

    有一个不错的 example for generating a record , 但这实际上只生成 3 个相同类型的值 float .

    最佳答案

    这不是一个坏主意——事实上,这是你能够做到这一点的关键。 FsCheck 的生成器是完全组合的。

    首先请注意,如果您有其构造函数采用原始类型的不可变对象(immutable对象),例如您的 Drink 和 Dish 的样子,FsCheck 可以开箱即用地生成这些对象(使用反射)

    let drinkArb = Arb.from<Drink>
    let dishArb = Arb.from<Dish>

    应该给你一个 Arbitrary 实例,它是一个生成器(生成一个随机 Drink 实例)和一个收缩器(获取一个 Drink 实例并使其“更小” - 这有助于调试,特别是对于复合结构,你会得到一个小计数器-例如,如果您的测试失败)。

    但是,这很快就崩溃了-在您的示例中,您可能不希望饮料数量或菜肴数量为负整数。上面的代码会生成负数。有时,如果您的类型实际上只是另一种类型的某种包装器,使用 Arb.convert,例如,这很容易解决。
    let drinksArb = Arb.Default.PositiveInt() |> Arb.convert (fun positive -> new Drinks(positive) (fun drinks -> drinks.Amount)

    您需要提供到 Arb.convert 和 presto 的往返转换,这是保持您的不变量的 Drinks 的新任意实例。当然,其他不变量可能不那么容易维护。

    之后,从这两部分同时生成生成器和收缩器变得有点困难。始终从生成器开始,然后如果(何时)需要它,收缩器会稍后出现。 @simonhdickson 的例子看起来很合理。如果您有上述任意实例,您可以通过调用 .Generator 来获取它们的生成器。
    let drinksGen = drinksArb.Generator

    一旦有了零件生成器(Drink 和 Dish),您确实可以按照@simonhdickson 的建议将它们组合在一起:
    let menuGenerator =
    Gen.map3 (fun a b c -> Menu(a,b,c)) (Gen.listOf dishGenerator) (Gen.listOf drinkGenerator) (Arb.generate<int>)

    分而治之!总的来说,看看 Gen 上的 intellisense 为您提供了一些关于如何组成生成器的想法。

    关于f# - 如何在 FsCheck 中生成 "complex"对象?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21988046/

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