对可能具有随机行为的方法进行单元测试

对可能具有随机行为的方法进行单元测试

Unit testing a method that can have random behaviour

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

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

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

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


单元测试在每次运行时都应该做同样的事情,否则您可能会遇到单元测试仅偶尔失败的情况,这可能是调试的真正痛苦。

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

如果您无法控制种子并且没有办法防止您正在测试的功能被随机化,那么我想您将陷入不可预测的单元测试。 :(


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

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


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

代码库中是否有任何东西可以检查生成的密码,以确保它们足够随机?如果没有,我可能会考虑创建逻辑来检查生成的密码,进行测试,然后可以指出随机密码生成器正在工作(因为"错误"的密码不会消失)。

一旦有了该逻辑,就可以编写一个集成类型测试,该测试将生成大量密码并将其传递给逻辑,这时您将了解随机密码生成的"效果"如何。


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

但是,这不能解决测试实现的问题,但这是一个如何测试依赖于随机性的典型方法的示例。

想象一下,我们实现了一个函数,该函数收集红色和蓝色大理石的集合并随机选择一个,但是可以为该概率分配权重,即权重2和1表示红色大理石的可能性为两倍。被选为蓝色大理石。

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

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


使用固定的随机种子或使其具有可重现性(即:从当日衍生)


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

牢记此原则,您可以尝试执行合理的次数,以使错误更正的机会几乎为零。但是,测试的任何一次失败都将使您除调试失败外,还要进行更广泛的测试。


在不知道规则是什么的情况下很难确定,但是假设它们类似"密码必须至少包含8个字符,并至少包含一个大写字母,一个小写字母,一个数字和一个特殊字符。"那么即使使用蛮力检查生成的密码以证明算法正确也是不可能的(因为这需要超过8 ^ 70 = 1.63x10 ^ 63次检查,具体取决于您指定使用多少个特殊字符,需要非常非常长的时间才能完成)。

最终,您所能做的就是测试尽可能多的密码,如果任何密码违反了规则,那么您知道该算法是错误的。最好的办法可能是让它整夜运行,如果早晨一切都好,您可能会没事的。

如果要在生产中加倍确定,请实现一个外部函数,该函数在循环中调用密码生成函数并对照规则进行检查。如果失败,则记录一条错误消息指出这一点(因此您知道需要修复)并生成另一个密码。继续直到获得符合规则的一个。


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

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


您可以为随机数生成器添加一个恒定值,以获取非随机结果并测试这些结果。


您还可以研究突变测试(Java的Jester,Ruby的Heckle)


好吧,考虑到它们是随机的,没有真正的方法可以确保,但是测试10万个密码应该可以消除大多数疑问:)


推荐阅读

    linux重置密码的命令?

    linux重置密码的命令?,密码,系统,服务,状态,情况,信息,位置,名称,平台,环境,

    linux新建组密码命令?

    linux新建组密码命令?,密码,管理,系统,代码,软件,第三,传播,用户组,命令,用

    linux命令密码过期?

    linux命令密码过期?,密码,系统,策略,名称,软件,信息,公司,首次,环境,代码,Lin

    linux密码更改命令?

    linux密码更改命令?,密码,系统,名称,信息,环境,命令,使用者,用户,权限,终端,L

    linux创建密码命令?

    linux创建密码命令?,密码,系统,地址,联系方式,软件,用户,用户名,位置,管理,

    linux命令设置密码?

    linux命令设置密码?,密码,系统,服务,软件,地址,电脑,流程,管理,用户,命令,问

    linux命令行密码联网?

    linux命令行密码联网?,密码,网络,系统,管理,地址,网址,数据,工具,环境,基础,

    linux密码长度命令?

    linux密码长度命令?,密码,数字,周期,信息,定期,代码,策略,时间,管理,大写字

    linux命令行界面密码?

    linux命令行界面密码?,密码,系统,管理,状态,代码,软件,地址,信息,标的,用户,

    linux清除密码命令?

    linux清除密码命令?,密码,系统,状态,名称,位置,网络,管理,软件,工具,命令,lin

    linux使用命令的方法?

    linux使用命令的方法?,系统,信息,工具,标准,数据,命令,左下角,目录,文件夹,

    linux锁屏密码命令?

    linux锁屏密码命令?,密码,系统,环境,图片,管理,信息,状态,名称,命令,用户,lin

    linux打命令输入密码?

    linux打命令输入密码?,密码,系统,状态,代码,管理,标的,位置,地址,名称,命令,L

    linux命令行更新密码?

    linux命令行更新密码?,密码,系统,名称,软件,信息,环境,命令,使用者,权限,用

    linux登录改密码命令?

    linux登录改密码命令?,密码,系统,名称,软件,状态,服务,信息,策略,环境,命令,

    删除密码命令linux?

    删除密码命令linux?,密码,系统,管理,电脑,软件,百度,信息,名称,名字,命令,lin

    linux串口命令行密码?

    linux串口命令行密码?,密码,系统,状态,信息,标的,地址,用户名,终端,用户,命

    linux中修改密码命令?

    linux中修改密码命令?,密码,系统,服务,名称,软件,信息,时间,状态,命令,用户,l

    linux锁定密码命令?

    linux锁定密码命令?,密码,系统,管理,信息,策略,状态,名称,软件,位置,环境,如

    linux看登录密码命令?

    linux看登录密码命令?,密码,系统,信息,地址,命令,用户,位置,设计,电脑,用户