如何为随机输出编写jUnit测试?

4
测试有预定义输入和输出参数的代码相对容易,但与编写具有一定随机性的代码测试相比,则需要检查随机生成器是否有偏差。一个使用随机数的库示例是java.util.Collections.shuffle(List<?> list),它可以对对象集合进行洗牌,遵循http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle算法。
如何为具有随机输出的代码编写jUnit测试?不仅适用于洗牌,还适用于随机性测试。

1
https://dev59.com/4nVD5IYBdhLWcg3wL4mM - Sotirios Delimanolis
stackoverflow.com/questions/56411/... 是关于洗牌的。这是问题的一个子部分。 - Alexandre Santos
@AlexandreSantos 为什么该问题的接受答案仍然不适用呢? - awksp
我猜输出有一定范围的值。那么,对于“n”次,输入随机范围的数据并收集输出结果,看每个输出是否具有相同的比率?如果比率相同,那么可以判断输出是随机的。 - Harry Cho
1个回答

1
除非您正在编写实际的随机数生成器或某种依赖于安全随机数生成器的加密库,否则您无需检查随机数生成器是否存在偏差。这是随机数生成器的作者的工作。
您提到的Collections.shuffle()也是一个糟糕的例子,因为它是一个内置的JDK方法。没有理由测试内置的JDK方法,Java的作者已经为您完成了这项工作,此外,在过去的20年中使用了这些方法的数百万用户也已经进行了测试。您是否还有测试来确认System.out.print()按预期工作?
单元测试应该是确定性的。重复运行相同的测试应该每次都产生相同的结果。如果测试失败,那么它是因为代码有缺陷还是因为非确定性输出产生了无效输入?如果重新运行结果,测试通过了,那么是因为漏洞已经被修复了还是因为我们碰巧得到了有效的随机输入?
出于这些原因,您的单元测试应该尝试模拟或存根任何随机性。也许编写几个测试来执行特定的数据转换以测试边界条件。例如,对于shuffle(),可以编写一个测试,将元素按特定顺序重新排序或按升序或降序排序元素,或者不执行任何转换等等。这些都是可能随机发生的有效结果。
这样,每次测试都会为相同的输入产生相同的输出,并且您可以获得不同结果的好处。
编辑 看起来您实际上想测试自己的随机数生成器。
以下是描述您应该执行的统计测试的链接,以查看它是否真正随机(或至少尽可能随机)。 RANDOM.ORG统计分析 NIST统计测试套件

我并没有表明我想要测试洗牌功能。我相信Sun/Oracle已经做好了这个功能。我只是把它作为一个随机代码的例子放在那里。然而,我也可以使用另一个例子,比如在线游戏网站的随机数生成器。对于在线游戏网站来说,随机数生成器的真正随机性非常重要。 - Alexandre Santos
@AlexandreSantos 添加了链接以实际测试随机数生成器。 - dkatzel
我也在想同样的问题。我知道我的方法是有效的,因为我在应用程序的主函数中看到了结果。不过,我对Junit测试还很陌生,我想知道如何使用Junit测试确定一副牌是否已经洗牌。从你的回答来看,似乎没有可能。对于最初提出问题的人,我建议你使用主函数运行该方法并查看输出。这就是我检查我的洗牌卡牌方法的方式。 - SedJ601
@SedrickJefferson 嗯,你可以一遍又一遍地洗牌,每次记录所有牌的位置。经过足够多次的洗牌之后,您可以制作所有牌和它们被洗到的位置的直方图。查看牌是否均匀分布在牌组的所有位置上。确保每次洗牌时都使用相同顺序的新牌组。这不会测试随机数生成器是否安全且不可预测,但至少可以告诉您牌正在进行洗牌。 - dkatzel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接