将基于 System.Random 的生成器变成 FsCheck 生成器

Turning a generator based on System.Random into an FsCheck generator

假设我有一个基于 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 实例(初始化成本可能很高)

有什么更好的方法吗?

下面的方法行得通吗?尽管 MyGen 本质上是随机的,但您可以通过 固定种子 :

使其具有确定性
let deterministicGen = MyGen(Random(42))

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

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

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

就像deterministicGen一样,deterministicValues是固定的:它是由MyGen生成的值列表。

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

let fsGen = Gen.elements deterministicValues

在这里,fsGen 是一个 Gen<'a>,其中 'aMyGen.Generate() returns.