Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 一个人如何生成一个;复杂的;FsCheck中的对象?_F#_Fscheck - Fatal编程技术网

F# 一个人如何生成一个;复杂的;FsCheck中的对象?

F# 一个人如何生成一个;复杂的;FsCheck中的对象?,f#,fscheck,F#,Fscheck,我想创建一个实例来生成“复杂”对象的实例。所谓复杂,我指的是C#中的一个现有类,它有许多子属性和集合。这些属性和集合反过来需要为它们生成数据 想象一下,这个类被命名为Menu,其中包含儿童收藏菜品和饮料(我在编造这个,所以忽略这个蹩脚的设计)。我想做以下工作: 生成数量可变的菜肴和数量可变的饮料 使用FsCheck API生成Dish和Drink实例以填充其属性 使用FsCheck API在菜单实例上设置一些其他基本属性 如何为这种类型的实例编写生成器?这是个坏主意吗?(我不熟悉基于属性的测

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

想象一下,这个类被命名为
Menu
,其中包含儿童收藏
菜品
饮料
(我在编造这个,所以忽略这个蹩脚的设计)。我想做以下工作:

  • 生成数量可变的
    菜肴
    和数量可变的
    饮料
  • 使用FsCheck API生成
    Dish
    Drink
    实例以填充其属性
  • 使用FsCheck API在
    菜单
    实例上设置一些其他基本属性
如何为这种类型的实例编写生成器?这是个坏主意吗?(我不熟悉基于属性的测试)。我已经阅读了这些文件,但显然到目前为止还没有将其全部内化


有一个很好的方法,但它实际上只生成了3个相同类型的值
float

可能有更好的方法来描述这个,但我认为这可能符合您的想法。每个
饮料
/
菜肴
类型都可以使用与
菜单生成器
相同的样式获取更多参数

type Drink() =
    member m.X = 1

type Dish() =
    member m.Y = 2

type Menu(dishes:Dish list, drinks:Drink list, total:int) =
    member m.Dishes = dishes
    member m.Drinks = drinks
    member m.Total = total

let drinkGenerator = Arb.generate<unit> |> Gen.map (fun () -> Drink())
let dishGenerator = Arb.generate<unit> |> Gen.map (fun () -> Dish())
let menuGenerator =
    Gen.map3 (fun a b c -> Menu(a,b,c)) <| Gen.listOf dishGenerator <| Gen.listOf drinkGenerator <| Arb.generate<int>
type饮料()=
成员m.X=1
类型盘()=
成员m.Y=2
类型菜单(菜肴:菜肴列表、饮料:饮料列表、总计:整数)=
成员m.盘子=盘子
成员m.饮料=饮料
成员m.总计=总计
让drinkGenerator=Arb.generate |>Gen.map(fun()->Drink())
让dishGenerator=Arb.generate |>Gen.map(fun()->Dish())
让menuGenerator=

Gen.map3(fun a b c->Menu(a,b,c))这不是一个坏主意-事实上,这是您能够做到这一点的全部要点。FsCheck的生成器是完全组合的

首先请注意,如果有不可变的对象,其构造函数采用基本类型,如饮料和菜肴的外观,则FsCheck可以直接生成这些对象(使用反射)

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

在这之后,从这两个部件同时生成生成器和收缩器就有点困难了。始终从发电机开始,如果需要,收缩器会在稍后出现@西蒙迪克森的例子看起来很合理。如果您有上述任意实例,您可以通过调用.generator访问它们的生成器

let drinksGen = drinksArb.Generator
一旦你有了零件生成器(饮料和盘子),你确实可以按照@simonhdickson的建议将它们组合在一起:

let menuGenerator =
    Gen.map3 (fun a b c -> Menu(a,b,c)) (Gen.listOf dishGenerator) (Gen.listOf drinkGenerator) (Arb.generate<int>)
让菜单生成器=
Gen.map3(fun a b c->Menu(a,b,c))(Gen.listOf dishGenerator)(Gen.listOf drinkGenerator)(Arb.generate)

分而治之!总的来说,看看Gen上的intellisense为您提供了什么,以了解如何组合生成器。

示例:@MauricioScheffer两个链接都已失效=(由于@MauricioScheffer的链接已失效,这里有一个指向日期时间生成器/收缩器代码的链接(猜测这可能是前面的示例之一).
generate
map3
…不必要的复杂IMHO。没错,您发布的链接示例远优于此。您能否提供一个C#示例?有关简单的C#示例,请参阅:
let drinksGen = drinksArb.Generator
let menuGenerator =
    Gen.map3 (fun a b c -> Menu(a,b,c)) (Gen.listOf dishGenerator) (Gen.listOf drinkGenerator) (Arb.generate<int>)