2011-05-20 26 views
7

我有一些基于加权随机递送事物的代码。更重的东西更可能随机选择。现在成为一名优秀的rubyist,我想用测试来涵盖所有这些代码。而且我想测试一下,根据正确的概率,事情正在被抓取。Ruby:在代码中使用rand()但编写测试来验证概率

那么我该如何测试呢?为应该是随机的东西创建测试使得很难比较实际与预期。我有几个想法,以及为什么他们不会很好地工作:

  • Stub Kernel.rand在我的测试中返回固定值。这很酷,但rand()被多次调用,我不确定我是否可以使用足够的控制来测试我需要的东西。

  • 获取一个随机项大量的次数,并比较实际比率与预期比率。但除非我可以无限次地运行它,否则这将永远不会完美,如果我在RNG中运气不好,可能会间歇性地失败。

  • 使用一致的随机种子。这使得RNG可重复使用,但它仍然无法证实项目A将在80%的时间内发生(例如)。

那么我可以用什么样的方法来编写随机概率的测试覆盖?

+0

您可以扩展最终的异议吗?为什么不能用种子PRNG测试你的分布曲线? – DigitalRoss 2011-05-20 22:16:58

+0

@DigitalRoss因为它仍然是随机的。所以如果我得到我想要的东西,10次中有3次实际上并没有告诉我是否满足25%的概率。提前知道随机值并没有什么帮助。 – 2011-05-20 22:54:28

回答

9

我认为你应该分开你的目标。其中之一就是要提到Kernel.rand。使用RSpec例如,你可以这样做:

test_values = [1, 2, 3] 
Kernel.stub!(:rand).and_return(*test_values) 

注意,该存根不会工作,除非你叫兰特与内核的接收器。如果你只是调用“rand”,那么当前的“self”将会收到该消息,而你实际上会得到一个随机数而不是test_values。

第二个目标是做一些类似于实际生成随机数的现场测试。然后,您会使用某种宽容来确保您接近所需的百分比。这绝不会是完美的,但可能需要一个人来评估结果。但它仍然是有用的,因为你可能会意识到另一个随机数生成器可能更好,比如从/ dev/random读取。另外,有这种测试是很好的,因为我们假设你决定迁移到一个新的平台上,这个平台的系统库不擅长产生随机性,或者某个版本存在一些缺陷。测试可能是一个警告标志。

这真的取决于你的目标。你只想测试你的加权算法,还是随机性?

+0

这是我错过的认知片断。像兰德存根这样使用多个返回值给我我需要的东西。我现在可以测试一个可预测的,完全均匀的价值分布,并确保他们做正确的事情。谢谢! – 2011-05-20 22:58:31

8

最好将Kernel.rand存根以返回固定值。

Kernel.rand不是你的代码。你应该假设它是有效的,而不是试图写测试来测试它而不是你的代码。并且使用您选择并明确编码的一组固定值比添加对特定种子的rand产生的依赖性更好。

0

用于测试,存根内核。兰德与以下简单而perfectly reasonable LCPRNG:

@@q = 0 
def r 
    @@q = 1_103_515_245 * @@q + 12_345 & 0xffff_ffff 
    (@@q >> 2)/0x3fff_ffff.to_f 
end 

你可能想直接跳过分配和使用的整数的结果,如果你的代码是兼容的,作为结果的所有位将被重复,而不仅仅是“最他们“。这将你的测试从“改进”中分离出来,并且允许你测试你的分布曲线。

+0

你刚刚打了我的脑海......但我无法弄清楚这是如何产生随机性的。 – 2014-05-08 21:53:01

3

如果你想下去一致种子的路线,看Kernel#srand

http://www.ruby-doc.org/core/classes/Kernel.html#M001387

引述文档(强调):

种子的伪随机数 发生器到号码的价值。如果 号码被省略或为零,则使用 时间,进程ID和序列 号码的组合来种子 发生器。 (这也是行为,如果 内核::兰特被称为无 以前调用函数srand,但没有 序列。)通过种子 设置为已知值,脚本可以在测试过程中进行 确定性。 返回先前的种子值。另外 参见Kernel :: rand。