可以通过不变测试替换单元测试吗?

Edw*_*ang 32 unit-testing quickcheck

作为一名程序员,我全心全意地购买了TDD理念,并努力为我编写的任何重要代码进行广泛的单元测试.有时这条道路可能会很痛苦(行为变化会导致多个单元测试的级联变化;需要大量的脚手架),但总的来说,我拒绝编程而没有我可以在每次更改后运行的测试,而且我的代码就像结果.

最近,我一直在玩Haskell,它是常驻测试库,QuickCheck.与TDD明显不同的是,QuickCheck强调测试代码的不变量,即保留输入的所有(或实质子集)的某些属性.一个简单的例子:一个稳定的排序算法应该给出相同的答案,如果我们运行它两次,应该有增加的输出,应该是输入的排列等.然后,QuickCheck生成各种随机数据,以测试这些不变量.

在我看来,至少对于纯函数(即没有副作用的函数 - 如果你正确地模拟你可以将脏函数转换成纯函数),那些不变测试可以取代单元测试作为这些函数的严格超集. .每个单元测试由输入和输出组成(在命令式编程语言中,"输出"不仅仅是函数的返回,而且还有任何已更改的状态,但这可以被封装).可以想象,可以创建一个随机输入生成器,它足以覆盖您手动创建的所有单元测试输入(然后是一些,因为它会产生您根本不会想到的情况); 如果由于某些边界条件而在程序中发现错误,则可以改进随机输入生成器,以便生成该情况.

那么,挑战在于是否有可能为每个问题制定有用的不变量.我要说的是:一旦你有一个答案,看它是否正确,首先计算答案就更简单了.对不变量的思考也有助于澄清复杂算法的规范,比特殊测试用例更好,这鼓励了对问题的逐个案例思考.您可以将程序的先前版本用作模型实现,或者使用另一种语言的程序版本.等等.最终,您可以覆盖所有以前的测试用例,而无需显式编码输入或输出.

我疯了,还是我做某事?

Edw*_*ang 22

一年后,我现在认为我对这个问题有一个答案:不!特别是,单元测试对于回归测试始终是必要且有用的,其中测试附加到错误报告并存在于代码库中以防止该错误再次发生.

但是,我怀疑任何单元测试都可以替换为随机生成输入的测试.即使在命令式代码的情况下,"输入"也是您需要做出的命令式语句的顺序.当然,是否值得创建随机数据生成器,以及是否可以使随机数据生成器具有正确的分布是另一个问题.单元测试只是一种退化情况,随机发生器总是给出相同的结果.

  • 你不能确保使用相同的随机种子吗?或者以某种方式保存生成的随机输入?这个答案似乎是基于基于属性的测试框架可能缺乏功能,而不是基于基于属性的测试本身的功能。 (2认同)

Ant*_*ony 9

你提出的是一个非常好的观点 - 只适用于函数式编程.你说过用命令式代码完成这一切的一种方法,但你也谈到了为什么没有完成 - 这并不是特别容易.

我认为这就是它不能取代单元测试的原因:它不适合命令式代码.

  • 它绝对可以 - 但它首先选择语言范式是相同的论点; 他们都"平等",但有些地方有些东西是不合适的.我认为这是其中一个案例. (2认同)