【问题标题】:Turning a generator based on System.Random into an FsCheck generator将基于 System.Random 的生成器变成 FsCheck 生成器
【发布时间】:2015-09-30 10:47:02
【问题描述】:

假设给了我一个基于System.Random 的生成器,我想把它变成一个 FsCheck 生成器:

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

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

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

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

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

有更好的方法吗?

【问题讨论】:

  • 我想重新设计MyGet 是不可能的?
  • 只要MyGen 从外部获取Random 实例,我们就可以通过像您建议的那样传递Random(42) 或传递从FsCheck 构建的实例将其转换为确定性函数随机上下文就像我的例子中一样

标签: f# fscheck


【解决方案1】:

以下方法可行吗?即使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

这里,fsGenGen<'a>,其中 'aMyGen.Generate() 返回的任何值。

【讨论】:

  • 这是一个聪明的主意!不是最终的解决方案,因为在某些情况下,您可能不想将选择限制为固定的集合;但在许多情况下,这可能是一个很好的折衷方案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-11
  • 2016-07-19
  • 1970-01-01
  • 2016-07-21
  • 2017-12-10
  • 1970-01-01
  • 2018-11-01
相关资源
最近更新 更多