Time will tell.
能畅快地书写代码是一大快事,想要解放自己,更多更快地写代码,就需要自动化来替代人工进行测试,谈到自动化,很容易想到的就是单元测试、接口测试、功能测试、性能测试、安全测试等等,其中部分环节常被忽略或是无法实施,而本章节则来探讨一下单元测试。
一、单元测试介绍
单元测试又称为模块测试,是针对程序模块来进行正确性检验的测试工作。
程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类、抽象类、或者派生类中的方法。
对于大多数同学来说,单元测试意味着非常细微粒度的测试,通常指方法级别的测试。而纯粹的方法级别单元测试,在我们看来性价比并不高,如果我们将单元测试的概念更加泛化,我们可以做到更加有效的测试,这里的有效包含两部分:一是有效率,二是有效果。
单元指最小可测部件,这个定义并没有对部件的粒度进行明确的定义,它可以是一个方法,可以是一个类,也可以是一个模块功能。通常来说,方法的封装更聚焦于单步功能的实现,而业务逻辑需要依赖多个方法串连完成,假如只聚焦在方法的测试上,会缺失业务逻辑链路的校验,对过于简单的方法做覆盖又发现不了问题。
所以基于精准测试分析,结合业务特征,以不同维度的单元测试用例覆盖,可以做到更少的用例覆盖更多场景分支,做到更为有效和高效。
以 chrome 的测试源码为例,其中约25%为功能性方法用例,其余75%为业务接口/集成测试用例,可见在 chrome 的自动化测试实现过程中,大部分也是围绕业务逻辑进行,而非单纯的方法级别单元测试。本文所探讨的对象,更多的也是与业务逻辑相关的可测单元。
二、为什么要做单元测试
Kent Beck 在其提出的极限编程(Extreme Programming,简称XP)中就使用单元测试作为质量保障的重要手段,也曾与设计模式四巨头之一 ErichGamma 共同开发了JUnit
用于单元测试,为后续 xUnit
系列框架的发展打下了基础。
有趣的是,在 stackoverflow 上一则关于《单元测试应该做到多细》的问题探讨上,Kent Beck 的回复却出乎很多人的意料,他并不推崇一定都要做单元测试,而更倾向于只针对于容易出错、没有信心的部分代码做测试。
这里认为,高质量的代码取决于设计编码的过程,测试仅是质量保障的最后一环,能找出程序的问题,并不能提升代码本身的质量,当对于自己的编码有足够的信心时,我们甚至可以不用进行测试。
当前测试环节之所以被认为必须,很大的一个原因就是因为不自信,害怕实现与需求不一致,害怕对于改动的影响评估不到位,希望能有一个靠谱的反馈,在代码改动时能告诉自己影响是什么,是不是符合需求,会不会导致历史功能受影响。所以在功能实现后希望测试同学介入,用大量的黑盒/灰盒/白盒 测试手段来验证代码修改。
但对于测试同学来说,黑盒的测试充斥着重复验证及不确定性,白盒虽然更具针对性但存在很高的理解分析成本,