写在前边

  目前对于单元测试,很多人的理解并不一样,执行起来更是千差万别。为了消除大多数的歧义,并使这篇文章尽量有说服力,这里我引用了很多来自于wikipedia.org,这个由世界上很多人共同维护的百科全书。以下的英语段落,都是我从http://en.wikipedia.org/wiki/Unit_testing摘录的。

  什么是单元测试?单元测试的目的是什么?

  In computer programming, unit testing is a software verification and validation method in which a programmer tests if individual units of source code are fit for use. A unit is the smallest testable part of an application. In procedural programming a unit may be an individual function or procedure.

  在计算机科学中,单元测试是一个有程序员测试源代码的个体单元是否适合使用的软件检测和验证方法。一个单元是一个应用程序的小的可测试部分。一个程序上的可编程单元可能是一个独立的函数或过程。

  解读:单元测试是程序员自己做的;单元测试是源代码级别的;

  The goal of unit testing is to isolate each part of the program and show that the individual parts are correct. A unit test provides a strict, written contract that the piece of code must satisfy. As a result, it affords several benefits. Unit tests find problems early in the development cycle.

  单元测试的目标是把程序隔离成很多小的部件,并确认这些独立的部件是正确的。一个单元测试提供了一个严谨的、文档化的、代码块必须满足的契约,所以单元测试可以带来很多好处。单元测试可以在开发早期发现问题。

  解读:终目的:早期发现问题;单元测试分两大步骤,1. 将程序隔离成小部件;2. 确认每个小部件都是正确的。

  什么是好的单元测试?

  我摘抄了《修改代码的艺术》中的一段。好的单元测试应该具备的品质:运行快;能帮助我们定位问题的所在。

  如果单元测试中跟数据库有交互、进行了网络通信、调用了文件系统、需要你对环境做特定的准备(如编写配置文件)才能运行,那单元测试不可能快。

  然后,我自己再加上两点:可以低成本的反复运行;可以容易的与正式代码一起重构。

  只有运行快、成本低,才能在程序员每次commit代码之前,运行全部的单元测试,验证其修改的代码是否已经影响到现有功能。

  单元测试与系统的可维护性

  合理规模的单元测试可以提高软件的可维护性。估计很多人都有类似的经验,一个大型程序,经过很多年的开发,已经变得很难维护,很少有人能搞清楚,如果改变某个模块的功能,对其他模块是否有影响,或有什么样的影响。往往,修改一点代码,不得不对整个软件做系统回归测试,这种测试的成本可能比修改代码的成本大的多。如果我们有合适的单元测试程序,可以帮助我们评估影响,减少回归测试的规模,那修改的风险会小很多。不过悲剧的是,大多数的开发项目经理迫于成本和时间的压力,都不考虑维护性的问题,架构师被迫只能在成本、时间与可维护性之间做出必要的妥协。如果架构师能让客户将可维护性加入非功能性需求,可以取得更多的资源来考虑这些了。

  单元测试与软件生命周期

  单元测试并不只是开发人员考虑的事情,应该在项目初始化阶段,由项目经理和架构师从项目管理和系统架构的高度考虑。

  1、项目初始阶段,确认我们需要对代码进行单元测试,并估算单元测试需要的成本

  在项目的初始化阶段,我们应该定义软件的质量目标。不同项目的质量目标是不一样的。对于火车控制系统、飞机控制系统、火箭控制系统来说,万分之零点一的错误率也是不能接受的;但我们却可以忍受Windows不经常性的蓝屏。所以,对于一些简单的,或不需要长期支持的项目(比如使用一次的移植脚本),我们并不需要为其编写单元测试。另外,也没有必要对项目中所有的代码进行单元测试。比如程序的展示层。如果某个模块的单元测试是必须的,我们必须在估算中安排合适的资源。由于单元测试需要一些必要的设计和开发模拟对象的工作,一般来说,对于管理信息系统,单元测试的工作量是正式代码的0.8到1.2倍之间;对于关键模块、系统框架等,可能需要1.5到2倍甚至更多的工作量。

  2、在架构设计阶段,要定义如何进行单元测试;并识别哪些资源是高成本资源,并制定对高成本资源的隔离计划

  如何进行单元测试是架构师规划、平衡系统框架时的重要工作。单元测试不单单影响我们的技术上的开发架构,也会对我们的开发流程产生很大的影响。比如提交流程中是否要求提交前必须运行所有的单元测试?单元测试中在什么地方做断言?如果组织单元测试代码等都需要架构师给出明确的文档,好有示例。另外,架构师要提供对于数据库交互、网络通信、文件系统、硬件接口等高成本资源的mock对象设计,并提供单元测试环境与运行环境如何切换的方案。

  (1)在详细设计阶段,定义每个逻辑分层职责、是否需要进行单元测试、如何进行单元测试。开始编写系统框架和高成本资源的模拟代码。
   (2)编写单元测试,并在代码commit前运行所有的单元测试,确认修改并没有影响到其他的功能;建立持续集成服务器,不断的在服务器上运行所有的单元测试代码,一旦发现有运行错误,立即通知开发人员修正。
  (3)维护阶段要同步更新单元测试代码。