软件测试的工作量很大(业界统计达到40% 到60%的总开发时间),而又有很大部分适于自动化,因此,测试的改进会对整个开发工作的质量、成本和周期带来非常显著的效果。
极限编程(XP)中推荐的自动化单元测试,是指在编写代码之前先写好测试代码,代码编到一定阶段就用写好的测试代码进行测试。自动化单元测试可以带来如下好处:
由于测试代码(测试用例)的不断增加,这些测试总让我们写出的代码往正确的方向靠拢,使我们不至于重犯以前的错误。
由于可以实现自动测试,所以可以很好的解决人工很难进行的回归测试问题。
我们沿着“建立测试=>令测试通过=>再建立测试=>再令测试通过”的模式,一步一步地把整个程序正确地开发出来。
1.测试代码的几个关键环节
对测试代码进行概括性分析,可以发现测试代码都具有类似的结构,每一个测试用例的执行都要包括测试数据初始化、运行要测试的代码、验证测试结果正确性三部分,见图1-1。
图1-1 测试代码的一般性流程
由于测试代码一般都包含了图1-1中的三部分,我们要改善测试代码使之具有良好的结构只要从这三方面入手即可。
1)将测试数据和测试结果从测试代码中分离出来
在采用CXXUNIT系列测试工具开发测试代码时,发现一般编程人员都是测试用例和测试代码混杂在一起,同样测试结果也是和测试代码混杂在一起,这样就导致测试用例和测试结果的管理非常困难,因为要管理每个用例的数据和结果实际上就是去管理这些代码。而且对于一个函数(或功能) 每增加新测试用例,就要多出一份类似的代码,代码的逻辑实际上都是一致的,和以前测试代码的不同点就是在初始化数据、测试结果的不同,这实际上也导致了代码的重复。
我们可以将测试数据和测试结果从测试代码中分离出来,使得某一个函数(或功能)的测试代码就一份,这一份测试代码应可以进行多组测试数据的测试,可以进行多组测试结果的验证。
2)将测试数据和测试结果放入文件中,并按目录存放
将测试数据和测试结果从测试代码中分离出来是为了更好的管理代码和测试数据,将每个测试用例的数据和结果都放入到一个文件中,文件名字或文件所在目录起上能表明测试用例含义的名字,这样管理起来就方便多了,见图1-2。
图1-2 测试用例文件及目录结构图
由图1-2中可以看出此时测试用例非常直观,从目录名就可以知道该目录下的为那个功能的测试用例,从测试用例文件名就可以知道这个测试用例测的哪一个方面。当一个功能的测试用例非常多可以分成许多类别时我们还可以在下面再创建测试用例分类子目录,使得不同类型的测试用例能分隔开方便管理(详见图2-1)。
3)将测试数据和测试结果绑定在一起
当每个测试用例对应的测试结果都一样时可以将测试结果嵌入到测试代码中,当不同的测试用例要对应不同的测试结果时,根据1)中论述应该将测试结果也从测试代码中分离出来。为了不混淆测试数据和测试结果之间的关系,将它们放在同一个文件中。这里举个例子,图1-2中的“闰年2月份的测试用例.ini”文件中内容如图1-3:
由图1-3可以看到,测试数据和测试结果放在一起,增加了可读性和维护性。
4) 一份测试代码来运行多份测试用例
怎样让一份测试程序可以进行多组数据的测试和结果的比较呢?3)中已经将测试用例分门别类,并由相应的目录结构组织起来。此时测试程序只需每次从测试目录中取出一个测试用例文件,进行初始化,然后执行测试,最后比较测试结果;测试完一个用例文件,再取下一个文件进行测试,如此循环直到所有的用例文件都测了一遍,详见图1-4。
图1-4一份测试代码测试多个测试用例的流程图
2.测试用例管理方案设计
若再加上边界数据要测试的数据组数就更多了,一般CXXUNIT系列编写的测试代码是每组测试数据(其实一组数据就对应一个测试用例)都要编写初始化代码,然后调用相应功能函数测试。这样导致:
在自动测试的整个过程中,测试用例的可维护性会影响到将来测试用例增加的难易度,良好的自测程序应能很方便的扩充测试用例。
在采用CXXUNIT系列测试工具开发测试代码时,对于一些简单的测试可以测试用例就嵌在测试代码中。但当某一个功能或函数要进行很多组数据(如边界数据)的测试时使用这种方法就得重复编写测试代码,可能每增加一个测试用例就要编写大量的重复测试代码。
举例:要测试周期会议预约功能的代码,要测试以下几组数据:
1)每日召开的周期会议
1.1)按召开次数预约的周期会议
1.2)按开始时间、终止时间预约的周期会议
2)每周召开的周期会议
……(内容和1.1、1.2一致)
3)每月召开的周期会议
……(内容和1.1、1.2一致)
4)每年召开的周期会议
……(内容和1.1、1.2一致)
随着测试数据组数的增加,将出现大量做重复动作的测试代码,这些测试代码之间唯一的不同是由于初始化的数据不一样而已。
当一个功能只需一两个测试用例时,测试用例嵌入在测试代码中可以进行控制和管理,当一个功能测试时需要大量的测试用例时(见举例),大量的测试用例嵌在代码中将很难管理,你要知道某个用例是否已经有了还得去遍历测试代码比较麻烦。
2.1测试用例目录结构