background image

 
这儿只列出了部分的可能测试,但是从这个列表我们可以看出单元测试的粒度。一个单元
测试基本是以一个对象的明确特性为基础,单元测试的过程应该限定在一个明确的线程
范围内。根据上面所述,一个单元测试的测试过程非常类似于一个 Use Case 的定义,但
是单元测试的粒度一般来说比 Use Case 的定义要小,这点是容易理解的,因为 Use 
Case 是以单独的事务单元为基础的,而单元测试是以一组聚合性很强的对象的特定特征
为基础的,一般而言一个事务中会利用许多的系统特征来完成具体的软件需求。
  从上面的分析我们可以得出,测试单元应该以一个对象的内部状态的转换为基本编
写单元。一个软件系统就和一辆设计好的汽车一样,系统的状态是由同一时刻时系统内部
的各个分立的部件的状态决定的,因此为了确定一个系统最终的行为符合我们起始的要
求,我们首先需要保证系统内的各个部分的状态会符合我们的设计要求,所以我们的测
试单元的重点应该放在确定对象的状态变换上。
  然而需要注意的并不是所有的对象组特征都需要被编写成独立的测试单元,如何在
对象组特征里筛选有价值的测试单元的原则在 JUnitTest Infected: Programmers Love 
Writing Tests 一文中得到了正确的描述,你应该在有可能引入错误的地方引入测试单元,
通常这些地方存在于有特定边界条件、复杂算法以及需求变动比较频繁的代码逻辑中。除
了这些特性需要被编写成独立的测试单元外,还有一些边界条件比较复杂的对象方法也
应该被编写成独立的测试单元,这部分单元测试已经在 Junit 文档中被较好的描述和解释
过了。
  在基本确定了需要编写的单元测试,我们还应该问自己:编写好了这些测试,我们
是否可以有把握地告诉自己,如果代码通过了这些单元测试,我们能认定程序的运行是
正确的,符合需求的。如果我们不能非常的确定,就应该看看是否还有遗漏的需要编写的
单元测试或者重新审视我们对软件需求的理解。通常来说,在开始使用单元测试的时候,
更多的单元测试总是没有错的。
  3. 如何编写单元测试
  在 XP 下强调单元测试必须由类包的编写者负责编写,这个限定对于我们设定的测
试目标是必须的。因为只有这样,测试才能保证对象的运行时态行为符合需求,而仅通过
类接口的测试,我们只能确保对象符合静态约束,因此这就要求我们在测试的过程中,
必须开放一定的内部数据结构,或者针对特定的运行行为建立适当的数据记录,并把这
些数据暴露给特定的测试单元。这也就是说我们在编写单元测试时必须对相应的类包进行
修改,这样的修改也发生在我们以前使用的测试方法中,因此以前的测试标记及其他一
些测试技巧仍然可以在 Junit 测试中改进使用。
  由于单元测试的总体目标是负责我们的软件在运行过程中的正确无误,因此在我们
对一个对象编写单元测试的时候,我们不但需要保证类的静态约束符合我们的设计意图 ,
而且需要保证对象在特定的条件下的运行状态符合我们的预先设定。还是拿数据库缓冲池
的例子说明,一个缓冲池暴露给其他对象的是一组使用接口,其中包括对池的参数设定、
池的初始化、池的销毁、从这个池里获得一个数据连接以及释放连接到池中,对其他对象
而言随着各种条件的触发而引起池的内部状态的变化是不需要知道的,这一点也是符合
封装原理的。但是池对象的状态变化,譬如:缓存的连接数在某些条件下会增长,一个连
接在足够长的运行后需要被彻底释放从而使池的连接被更新等等,虽然外部对象不需要
明确,但是却是程序运行正确的保证,所以我们的单元测试必须保证这些内部逻辑被正
确的运行。
  编译语言的测试和调试是很难对运行的逻辑过程进行跟踪的,但是我们知道,无论