3

假设我有一个基于的生成器,System.Random并且我想将它变成一个 FsCheck 生成器:

let myGen = MyGen(System.Random())
let fsGen = gen { return myGen.Generate() }

这个简单的解决方案有几个问题:首先是忽略了大小的概念;我认为这不是一个大问题,许多生成器忽略了大小。另一个问题会影响可重复性,因为 FsCheck 生成器是底层的纯函数,随机性仅由测试运行器中的采样机制提供。(这在这个答案中有清楚的解释)。

现在,一个解决方案可能是:

let fsGen = 
    gen {
        let! seed = Gen.choose(0, System.Int32.MaxValue)
        let myGen = MyGen(System.Random(seed))
        return myGen.Generate() }

但是有性能损失,因为我MyGen每次都必须创建一个新实例(初始化成本可能很高)

有更好的办法吗?

4

1 回答 1

4

以下工作可以吗?即使本质上是随机的,您也可以通过修复种子MyGen使其具有确定性:

let deterministicGen = MyGen(Random(42))

由于 的性质Random,这不能保证具有足够随机的分布,但如果它符合您的目的,您可以创建由 生成的确定性值序列MyGen

let deterministicValues = List.init 100 (fun _ -> deterministicGen.Generate())

这只有 100 个值,但根据您的需要,您可以创建一个更大的 1000 个样本集,甚至可能是 10000 个值。

就像deterministicGen,deterministicValues是固定的:它是由MyGen.

您可以轻松地让 FsCheck 从此列表中随机选择值:

let fsGen = Gen.elements deterministicValues

在这里,fsGen是一个Gen<'a>'a无论MyGen.Generate()返回哪里。

于 2015-09-30T12:11:10.013 回答