集成测试
增量与非增量测试
非增量测试或“崩溃”测试:软件测试先应先独立地测试每个模块,然后再将这些模块组装成完整的程序
增量测试或集成测试:先将下一步要测试的模块组装到测试完成的模块集合中,然后再进行测试
如上图所示的程序可作为一个例子,矩形框代表程序的6个模块(子程序或过程),连接模块间的线条代表程序的控制层次,模块A调用模块B、C和D,模块B调用模块E,模块D调用模块F。非增量测试首先对6个模块中的每一个模块进行单独的模块测试,将每个模块视为一个独立实体,这些模块可以同时或按次序进行测试。最后,将这些模块组装或集成为完整的程序。
测试单独的模块需要驱动模块(driver module)和一个或多个桩模块(stub module)。举例来说,测试模块B,首先要设计测试用例,然后将测试用例作为输入参数由驱动模块传递给模块B。驱动模块是测试人员编写的一个小模块,用来将测试用例驱动或传输到被测模块中。驱动模块还必须向测试人员显示模块B的结果。此外,由于模块B调用了模块E,所以还必须使用一个额外的组件,该组件在模块B调用模块E时接受模块B的控制指令。这就由桩模块来完成,它是一个被命名为“E”的特殊模块,用来模拟模块E的功能。当所有6个模块的模块测试都完成之后,就将这些模块组装成完整的程序。
另一种可选择的方法是增量测试。不同于独立地测试每个模块,增量测试首先将下一个要测试的模块组装到前面已经测试过的模块集合中去。暂且假设从底部开始测试。第一步先测试模块E、C和F,可以并行测试(由三个人进行),也可串行进行。请注意,我们必须要为每个模块准备一个驱动模块,但不是桩模块。下一步是测试模块B和D,但不是单独地测试它们,而是分别将其与模块E和F组装在一起。换言之,要测试模块B,应编写驱动模块并集成测试用例,将模块B和E组合起来测试。将下一个要测试的模块组装到前面已经测试过的模块集合或子集中去,这个增长的过程会一致进行到测试完最后一个模块(本例中是模块A)为止。这个过程也可以自顶向下进行。
增量与非增量测试结论:
1、非增量测试所需的工作量要多一些。对于图1所示的程序,需要准备5个驱动模块和5个桩模块(假设顶部的模块不需要驱动模块)。自底向上的增量测试需要5个驱动模块,但不需要桩模块。自顶向下的增量测试需要5个桩模块,但不需要驱动模块。增量测试所需的工作量要少一些,因为使用了前面测试过的模块来取代非增量测试中所需要的驱动模块(如果从顶部开始测试)或桩模块(如果从底部开始测试)。
2.如果使用了增量测试,可以较早地发现模块中与不匹配接口、不正确假设相关的编程错误。这是由于今早地对模块组合进行了集成测试。然而,如果采用非增量测试,只有到了测试过程的最后阶段,模块之间才能“互相看到”。
3.如果使用了增量测试,调试会进行的容易一些。我们假定存在着与模块间接口或假设相关的编程错误(根据经验而来的合理假设),那么,如果使用非增量测试,直到整个程序组装之后,这些错误才会浮现出来。到了这个时候,我们就难以定位,因为它可能存在于程序内部的任何位置。相反,如果使用增量测试,这种类型的错误就很容易发现,因为该错误很可能与最近添加的模块有关。
4.增量测试会将测试进行的更彻底。如果当前正在测试模块B,要么是模块E,要么是模块A(取决于测试是从底部还是从顶部开始的)被当做结果而执行。虽然模块E或模块A先前已经进行了完全的测试,但将其作为B的模块测试结果而执行,则会诱发出一个新的情况,可能会暴露出先前测试过的模块E或模块A中存在的一个新缺陷。另一方面,如果使用的是费增量测试,对模块B的测试仅影响到其本身。换言之,增量测试使用先前测试过的模块,取代了非增量测试中使用的桩模块或驱动模块。因此,到最后一个模块测试完成时,实际的模块经受到了更多的检验。
5.非增量测试所占用的机器时间显得少一些。如果使用自底向上的方法测试图1中的模块A,在执行A的过程中,模块B、C、D、E和F也会执行到。而在对模块A的非增量测试中,仅会执行模块B、C和E的桩模块。自顶向下的增量测试的情况也是如此。如果测试的是模块F,那么在执行模块F时还会执行模块A、B、C、D和E,而在对模块F的非增量测试中,仅有模块F的驱动模块与其一起执行。因此,完成一次增量测试所需执行的机器指令,显然多于采用非增量测试方法所需的指令。但此消彼长的是,非增量测试要比增量测试需要更多的驱动模块和桩模块,开发这些驱动模块和桩模块是要占用机器时间的。
6.模块测试阶段开始时,如果使用的是非增量测试,就会有更多的机会进行并行操作(所有的模块可以同时测试)
集成测试之自顶向下、自底向上、三明治集成
以下图为例子阐述三种集成测试的方式,A至L代表程序的12个模块。假定模块J包含程序的I/O读操作,而模块I包含I/O写操作。

1、自顶向下测试
目的:从顶层控制(主控模块)开始,采用同设计顺序一样的思路对被测系统进行测试,来验证系统的稳定性。
定义:自顶向下的集成测试就是按照系统层次结构图,以主程序模块为中心,自上而下按照深度优先或者广度优先策略,对各个模块一边组装一边进行测试。
测试开始之后,挑选哪一个后续模块进行增量测试唯一的原则是:要成为合乎条件的下一个模块,至少一个该模块的从属模块(调用它的模块)事先经过了测试。
第一步是测试模块A,测试要求必须编写出代表B、C和D的桩模块。
第二部模块A测试完成之后,就用一个实际的模块代替其中的一个桩模块,而该模块需要的桩模块也被添加进来(如下图)
测试完顶部模块之后,接下来可能的测试序列有很多。举例来说,如果我们要执行所有的测试序列,大量可能的模块序列中的四个序列如下:
1.A B C D E F G H I J K L
2.A B E F J C G K D H L I
3.A D H I K L C G B F J E
4.A B F J D I E C G K H L
如果可以进行并行测试,可能还有其他的选择。举例来说,模块A测试结束之后,一位程序员可能会选取模块A,测试模块A-B的组合,另一位程序员可能会测试模块A-C的组合,而第三位程序员可能会测试模块A-D的组合,总的来说,不存在最佳的模块序列,但却有下面可供考虑的两项指南:
1.如果程序中存在关键部分(例如模块G),那么在设计模块序列时就应将这些关键模块尽可能早地添加进去。所谓“关键部分”可能是某个复杂的模块、某个采用新算法的模块或某个被怀疑容易发生错误的模块。
2.在设计模块序列时,应将I/O模块尽可能早地添加进来。
如果模块J和模块I是I/O模块,而模块G执行某些关键操作,那么增长序列可能是:
A B F J D I C G E K H L 类比数据结构中树中深度广度优先遍历
2、自底向上测试
目的:从依赖性最小的底层模块开始,按照层次结构图,逐层向上集成,验证系统的稳定性。
定义:自底向上集成是从系统层次结构图的最底层模块开始进行组装和集成测试的方式。对于某一个层次的特定模块,因为它的子模块(包括子模块的所有下属模块)已经组装并测试完成,所以不再需要桩模块。在测试过程中,如果想要从子模块得到信息可以通过直接运行子模块得到。也就是说,在集成测试的过程中只需要开发相应的驱动模块就可以了。
测试开始之后,挑选哪一个后续模块进行增量测试唯一的原则是:要成为合乎条件的下一个模块,该模块所有的从属模块(它调用的模块)都已经事先经过了测试。
第一步是测试E、J、G、K、L和I中的部分或全部模块,既可以串行进行,也可以并行进行。要做到这一点,每一模块都需要一个特殊的驱动模块:既包含着有效的测试输入、调用被测模块且将输出显示出来(或将实际输出与预期输出作比较)的模块。有别于使用桩模块的情况,由于驱动模块可以交迭地调用被测模块,因此不需要为驱动模块提供多个版本。在大多数情况下,开发驱动模块要比开发桩模块更容易些。影响测试序列的因素是模块的关键程度,
如果模块D和模块F最为关键,那么应该自底向上增量测试的某个中间状态可能如下图所示。接下来的步骤可能是测试模块E,然后再测试模块B,将模块B与先前测试过的模块E、F和J组装起来进行测试。

3、三明治集成测试
定义:三明治集成是一种混合增殖式测试策略,综合了自顶向下和自底向上两种集成方法的优点,因此也属于基于功能分解集成。如果借助图来介绍三明治集成的话,就是在各个子树上真正进行大爆炸集成。桩和驱动器的开发工作都比较小,不过代价是作为大爆炸集成的后果,在一定程度上增加了定位缺陷的难度。
- 方法: 一般对软件结构的上层使用自顶向下结合的方法; 对下层使用自底向上结合的方法;
- 步骤: 首先,确定以哪一层为界来决定使用三明治集成策略。我们确定以B-C-D模块为分层界; 其次,对分层界及其下面的各层使用自底向上的集成策略;再次,对分层界上面的层次使用自顶向下的集成策略; 然后,把分层界各模块同相应的下层集成; 最后,对系统进行整体测试。
缺点: 1、在被集成之前,中间层不能尽早得到充分的测试。(针对该缺点可以对分界层使用使用独立测试策略,即对该层模块设计桩模块和驱动模块完成对目标层的测试,充分发挥测试的并行性,弥补三明治集中不能充分测试中间层的缺点) 2、中间层如果选择不适当,可能会增加驱动模块的和桩模块工作量的设计负担。
4、 自顶向下和自底向上两种测试方法的优缺点
自顶向下
| 优点 | 缺点 |
|---|---|
| 1、如果主要的缺陷发生在顶层将非常有利 | 1、必须开发桩模块 |
| 2、一旦引入I/O功能,提交测试用例会更容易 | 2、桩模块比最初表现得更复杂 |
| 3、早期的程序框架可以进行演示,并可激发积极性 | 3、在引入I/O功能前,向模块引入测试用例比较困难 |
| —— | 4、创建测试环境困难 |
| —— | 5、观察测试输出困难 |
| —— | 6、使人误解设计和测试可以交迭进行 |
| —— | 7、会导致特定模块测试的完成延后 |
自底向上
| 优点 | 缺点 |
|---|---|
| 1、如果主要的缺陷发生在顶层将非常有利 | 1、必须开发驱动模块 |
| 2、测试环境比较容易建立 | 2、直到最后一个模块添加进去,程序才形成一个整体 |
| 3、观察测试输出比较容易 | —— |