如何产生一种“复杂"信号? FsCheck中的对象? [英] How does one generate a "complex" object in FsCheck?

查看:61
本文介绍了如何产生一种“复杂"信号? FsCheck中的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个

I'd like to create an FsCheck Generator to generate instances of a "complex" object. By complex, I mean an existing class in C# that has a number of child properties and collections. These properties and collections in turn need to have data generated for them.

想象一下,该类被命名为Menu,其子集合为DishesDrinks(我正在做这个,所以请忽略笨拙的设计).我要执行以下操作:

Imagine this class was named Menu with child collections Dishes and Drinks (I'm making this up so ignore the crappy design). I want to do the following:

  • 生成可变数量的Dishes和可变数量的Drinks.
  • 使用FsCheck API生成DishDrink实例以填充其属性.
  • 使用FsCheck API在Menu实例上设置其他一些原始属性.
  • Generate a variable number of Dishes and a variable number of Drinks.
  • Generate the Dish and Drink instances using the FsCheck API to populate their properties.
  • Set some other primitive properties on the Menu instance using the FsCheck API.

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

How does one go about writing a generator for this type of instance? Is this a bad idea? (I'm new to property based testing). I have read the docs, but have clearly failed to internalise it all so far.

有一个不错的

There is a nice example for generating a record, but this is really only generating 3 values of the same type float.

推荐答案

这不是一个坏主意-实际上,这是您能够做到这一点的全部. FsCheck的生成器完全是合成的.

This is not a bad idea - in fact it's the whole point that you are able to do this. FsCheck's generators are fully compositional.

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

Note first that if you have immutable objects whose constructors take primitive types, like your Drink and Dish looks like, FsCheck can generate these out of the box (using reflection)

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

应该为您提供一个任意实例,该实例是一个生成器(生成一个随机Drink实例)和一个收缩器(使用Drink实例并使它变小)-这有助于调试,尤其是对于复合结构,您可以在其中进行调试一个小的反例(如果您的测试失败).

should give you an Arbitrary instance, which is a generator (generates a random Drink instance) and a shrinker (takes a Drink instance and makes it 'smaller' - this helps with debugging, esp. for composite structures, where you get a small counter-example if your test fails).

这很快就分解了-在您的示例中,您可能不希望饮料或菜肴的数量为负整数.上面的代码将生成负数.有时候,如果您的类型实际上只是某种类型的包装,可以使用Arb.convert例如,

This breaks down fairly quickly though - in your example you probably don't want negative integers for the number of drinks or the number of dishes. The above code will generate negative numbers though. Sometimes this is easy to fix if your type is really just a wrapper of some sort around another type, using Arb.convert, e.g.

let drinksArb = Arb.Default.PositiveInt() |> Arb.convert (fun positive -> new Drinks(positive) (fun drinks -> drinks.Amount)

您需要提供Arb.convert和presto之间的转换,以及用于Drinks的新任意实例,以保持您的不变性.当然,其他不变式可能不太容易维护.

You need to provide to and from conversions to Arb.convert and presto, new arbitrary instance for Drinks that maintains your invariant. Other invariants may not be so easy to maintain of course.

之后,从这两个部件同时生成生成器和收缩器会变得有些困难.始终从发电机开始,然后(如果需要)稍后再出现收缩器. @simonhdickson的示例看起来很合理.如果您具有上述任意实例,则可以通过调用.Generator来获取它们的生成器.

After that it becomes a bit harder to generate a generator and a shrinker at the same time from those two pieces. Always start with the generator, then shrinker comes later if (when) you need it. @simonhdickson's example looks reasonable. If you have the arbitrary instances above, you can get at their generator by calling .Generator.

let drinksGen = drinksArb.Generator

一旦有了零件生成器(Drink和Dish),您就可以按照@simonhdickson的建议将它们组合在一起:

Once you have the parts generators (Drink and Dish), you can indeed compose them together as @simonhdickson proposes:

let menuGenerator =
    Gen.map3 (fun a b c -> Menu(a,b,c)) (Gen.listOf dishGenerator) (Gen.listOf drinkGenerator) (Arb.generate<int>)

分而治之!总体看一看Gen上的intellisense能为您提供一些有关如何组成生成器的想法.

Divide and conquer! Overall have a look at what intellisense on Gen gives you to get some ideas of how to compose generators.

这篇关于如何产生一种“复杂"信号? FsCheck中的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆