我有一个调用choose(elems) -> elem
的函数rand()
,这使得它不确定。
为了能够更好地测试这个,我想我可以把这个功能分成两部分,
generate_choices(elems, ...) -> distribution
choose(distribution) -> elem
其中choose()
是rand()
周围的薄包装,generate_choices()
生成一个用于绘制元素的分布。然后我可以确定地测试这个概率分布是否符合预期。
分布是统一的但是有两个条件:
elems
不够,请统一添加随机后备元素。elems
,请统一添加随机默认元素。一些例子:
generate_choices([a, b, c, d], [], []) -> [a, b, c, d]
generate_choices([a, b, c], [fallback1], []) -> [a, b, c, fallback1]
generate_choices([a, b, c], [fb1, fb2], []) -> [a, b, c, (fb1 | fb2)]
generate_choices([a, b], [fb1, fb2], [default1]) -> [a, b, (fb1 | fb2), default1]
generate_choices([a, b], [fb1, fb2], [d1, d2]) -> [a, b, (fb1 | fb2), (d1 | d2) ]
generate_choices([a], [fb1, fb2], [d1, d2]) -> [a, (fb1|fb2), (d1|d2) ]
我的问题是:我应该如何建模distribution
?
rand()
内拨打generate_choices()
来填充后备和默认,那么我只能测试一些generate_choices()
的确定性部分。(elems, fallback, default)
,那么generate_choices()
是完全确定的,但choice()
变得不那么简单,无论如何都必须进行更彻底的测试。答案 0 :(得分:2)
至少有两种方法可以测试使用随机数的函数。您可能希望进行两种测试。
(1)一种是设置随机数发生器的初始状态并生成一些示例,并通过检查验证示例是正确的。然后将这些示例作为预期输出放入测试脚本中,并在脚本开头设置相同的初始状态。
(2)另一种测试是生成大量示例,并验证平均来说,示例满足预期的属性。这是一种非确定性测试,因为对于由随机数生成器生成的某些序列,测试可能会失败。你必须接受一些小的失败概率;好消息是,通过测试大量示例并使测试的容差足够大,可以使概率足够小。
(2a)例如,在最简单的情况下,输入是一个序列,输出是该序列的排列。如果生成大量示例,则应该发现所有排列在一定容差范围内具有相同的频率。显然这个测试受到测试输入长度的限制,因为有n!长度为n的输入的排列。
您可以通过考虑每个不同排列的比例的分布来推导公差。每个置换具有概率1 / n!,并且每个置换的预期数量是(m乘以1 / n!),其中m是生成的排列的数量。每个排列数的方差是(m乘以1 / n!倍(1-1 / n!)),标准差是平方根。您可以将公差间隔近似为(预期数量加上或减去标准偏差的倍数)。您可以通过更仔细地考虑分布来获得更精确的间隔。
(2b)另一种测试排列的方法是查看输出的第一个元素等于输入的第一个元素的次数,输出的第一个元素等于输入的第二个元素,输入的第一个元素等于输入的第三个元素,...,输入的第二个元素,......,第三个元素,......输入的最后一个元素。对于比测试2a更长的序列,这可能是可行的。游戏再一次是弄清楚每个箱子中预期数字的分布,并从中得出一个容差。