单元测试可以具有随机行为的方法

时间:2008-09-17 21:46:18

标签: unit-testing random

今天下午我遇到了这种情况,所以我想我会问你们做了什么。

我们有一个用于用户密码重置的随机密码生成器,在修复问题时,我决定将例程移到我的(慢慢增长的)测试工具中。

我想测试生成的密码是否符合我们设定的规则,但当然函数的结果将是随机的(或者,伪随机化)。

你们在单元测试中会做什么?生成一堆密码,检查它们是否全部通过,并认为它足够好?

11 个答案:

答案 0 :(得分:8)

单元测试每次运行都应该做同样的事情,否则你可能会遇到单元测试偶尔失败的情况,这可能是一个真正的调试难题。

每次尝试使用相同的种子播种伪随机数(在测试中,即 - 不在生产代码中)。这样,您的测试每次都会生成相同的输入集。

如果您无法控制种子,并且无法阻止您正在测试的功能被随机化,那么我猜您会遇到不可预测的单元测试。 :(

答案 1 :(得分:4)

该函数假设对于所有输入,输出符合规范。单元测试是试图伪造该假设。所以,是的,在这种情况下你能做的最好的事情就是产生大量的输出。如果它们都通过了您的规范,那么您可以合理地确定您的函数按指定的方式工作。

考虑将随机数生成器放在此函数之外并向其传递一个随机数,使函数具有确定性,而不是让它直接访问随机数生成器。这样,您可以在测试工具中生成大量随机输入,将它们全部传递给您的函数,并测试输出。如果一个失败,记录该值是什么,以便您有一个记录的测试用例。

答案 2 :(得分:2)

除了测试一些以确保它们通过之外,我还会编写一个测试来确保打破规则的密码失败。

代码库中是否有任何内容可以检查生成的密码以确保它们足够随机?如果没有,我可能会考虑创建逻辑来检查生成的密码,测试它,然后你可以说随机密码生成器正在工作(因为“坏”的密码生成器不会出来)。

一旦你有了这个逻辑,你就可以编写一个集成类型测试,它会生成大量密码并通过逻辑传递,此时你就会知道你的随机密码生成的“好”是多少

答案 3 :(得分:0)

嗯,考虑到它们是随机的,没有真正的方法可以确定,但测试100 000密码应该清除大多数疑问:)

答案 4 :(得分:0)

您还可以查看变异测试(Jester表示Java,Heckle表示Ruby)

答案 5 :(得分:0)

您可以使用常量值为随机数生成器播种,以获得非随机结果并测试这些结果。

答案 6 :(得分:0)

我假设用户输入的密码符合与随机生成的密码相同的限制。因此,您可能希望拥有一组用于检查已知条件的静态密码,然后您将拥有一个执行动态密码检查的循环。循环的大小并不太重要,但它应该足够大,以便从生成器中获得温暖的模糊感,但不要太大,以至于您的测试需要永远运行。如果随着时间推移出现任何问题,您可以将这些案例添加到静态列表中。

从长远来看,弱密码不会破坏您的程序,密码安全性落在用户手中。因此,您的首要任务是确保动态生成和强度检查不会破坏系统。

答案 7 :(得分:0)

不知道你的规则是什么,很难肯定,但假设它们是“密码必须至少8个字符,至少有一个大写字母,一个小写字母,一个数字和一个特殊字符“那么即使用蛮力来检查足够数量的生成密码来证明算法是正确的也是不可能的(因为这需要超过8 ^ 70 = 1.63x10 ^ 63的检查,具体取决于你指定使用的特殊字符数,这将是需要很长时间才能完成。

最终,您所能做的就是尽可能多地测试密码,如果违反了规则,那么您就知道算法不正确。可能最好的办法是让它在一夜之间运行,如果早上一切顺利,你很可能会好起来。

如果你想在生产中加倍确定,那么实现一个外部函数,在循环中调用密码生成函数并根据规则进行检查。如果失败,则记录一个错误,指出这一点(因此您知道需要修复它)并生成另一个密码。继续,直到你得到一个符合规则。

答案 8 :(得分:0)

在我的拙见中,你不希望有时会通过测试但有时会失败。有些人甚至可能认为这种测试不是单元测试。但主要的想法是当你看到绿色条时确保功能正常。

考虑到这一原则,你可能会尝试执行一次合理的次数,以便错误纠正的几率几乎为cero。然而,测试的单一失败将迫使你进行更广泛的测试,除了重新组合失败。

答案 9 :(得分:0)

使用固定的随机种子或使其可重复(即:从当天获得)

答案 10 :(得分:0)

首先,为您的PRNG使用种子。您的输入不再是随机的,并且摆脱了不可预测的输出问题 - 即现在您的单元测试是确定性的。

然而,这并没有解决测试实现的问题,但这里是一个如何测试依赖随机性的典型方法的例子。

想象一下,我们已经实现了一个功能,它采用红色和蓝色大理石的集合并随机选择一个,但是可以为概率分配权重,即权重2和1意味着红色大理石的可能性是被选为蓝色大理石。

我们可以通过将一个选项的权重设置为零并验证在所有情况下(实际上,对于大量的测试输入)来测试这一点,我们总是得到例如蓝色大理石。然后反转重量应该得到相反的结果(所有红色大理石)。

这并不能保证我们的功能符合预期(如果我们传递相同数量的红色和蓝色弹珠并且具有相同的权重,我们总是在大量试验中得到50/50分布吗?)但是练习通常就足够了。