将基于 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>
,其中 'a
是 MyGen.Generate()
returns.
假设我有一个基于 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>
,其中 'a
是 MyGen.Generate()
returns.