单元测试Unit Test
很早就知道单元测试这样一个概念,但直到几个月前,我真正开始接触和使用它。究竟什么是单元测试?我想也许很多使用了很久的人也不一定能描述的十分清楚,所以写了这篇文章来尝试描述它的特征和原则,以帮助更多人。
什么是单元测试?
先来看看单 元测试的定义,在维基百科英文版中可以找到Kolawa Adam在 Automated Defect Prevention: Best Practices in Software Management 一书中对单元测试的定义:
In computer programming, unit testing is a method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures are tested to determine if they are fit for use.
重点在于最后,单元测试的目的显而易见,用来确定是否适合使用。而测试的方法则包括控制数据,使用和操作过程。那么以我的理解,每个单元测试就是一段用于测试一个模块或接口是否能达到预期结果的代码。开发人员需要使用代码来定义一个可用的衡量标准,并且可以快速检验。 很快我发现有一个误区,许多人认为单元测试必须是一个runner集中运行所有单元的测试,并一目了然。不,这仅仅是一种自动化单元测试的最佳实践,在一些小型项目中单元测试可能仅仅是一组去除其他特性的接口调用。甚至在一些图形处理或布局的项目中单元测试可以结合自身特性变的十分有趣,比如 Masonry ,一个网格布局库,在它的单元测试中不是一个红或绿的条目,而是一行一行的小格布局用以说明布局被完成的事实,这样比代码检查布局是否正确再以颜色显示结果来得更直观高效,也避免了测试程序本身的bug导致的失误。 打个比方,单元测试就像一把尺子,当测量的对象是一个曲面时,也许可以花费大力气去将它抽象成平面,但我更提倡量身定做一把弯曲的尺子去适应这个曲面。无论怎样,单元测试是为了生产代码而写,它应当足够的自由奔放,去适应各种各样的生产代码。
为什么要单元测试?
也许定义中已经很清楚的指明了其意义,确认某段代码或模块或接口是否适合使用,但我想会有更多的人认为,直接在测试环境中使用软件可以更加确保软件是否可用。不,在实际使用过程中会伴随着一大批的附带操作大量增加测试时间,并且无法保证其测试覆盖率。所以我认为单元测试的目的并不仅仅是确认是否可用,而是更高效更稳定的确认其是否可用。 随着项目规模的增加,函数、方法、变量都在递增,尤其是进度的不足,来自产品经理的压力,还有QA所带来的各种Bug报告会让原本整洁的代码变得一片混乱。我甚至见过同一个接口以不同的名称出现在8个不同的控制器中。这时也许我们首先想到的是重构,可是等等,在重构结束时我们如何确定项目仅仅是被重构了,而不是被改写了?此时单元测试将是一根救命稻草,它是一个衡量标准,告诉开发人员这么做是否将改变结果。 不仅仅是这样。许多人认为单元测试,甚至整个测试都是在编码结束后的一道工序,而修复bug也不过是在做垃圾掩埋一类的工作。但测试应该伴随整个编码或软件周期进行,还有将在后面提到的TDD这样有趣的东西,单元测试将超前于编码。我的意思是,单元测试应该是一个框架、标准,经常被形容被脚手架,像建筑一样,脚手架的高度至少应该和大楼高度不相上下,甚至一开始就搭好脚手架。