第一节 软件测试基本理论与方法
一、软件测试基础
1.软件测试的目标
G.Myers给出了关于测试的一些规则,这些规则可以看做是测试的目标或定义。
(1)测试是为了发现程序中的错误而执行程序的过程。
(2)好的测试方案是极可能发现迄今为止尚未发现错误的测试方案。
(3)成功的测试是发现了至今为止尚未发现错误的测试。
从上述规则可以看出,测试的正确定义是“为了发现程序中的错误而执行程序的过程”。测试方案的设计应力求最能暴露程序中存在的错误。
此外,即使经过了最严格的测试之后,仍然可能还有没被发现的错误潜藏在程序中,因此测试决不能证明程序是正确的。
2.软件测试准则
为了能设计出有效的测试方案,软件测试工程师必须深入理解并正确运用指导软件测试的基本准则。
(1)所有测试都应该能追溯到系统需求。
(2)应该远在测试开始之前就制定出测试计划。
(3)把Pareto原理应用到软件测试中。Pareto原理说明,测试发现的错误中的80%很可能是由程序中20%的模块造成的。
(4)应该从“小规模”测试开始,并逐步进行“大规模”测试。
(5)穷举测试是不可能的。
(6)为了达到最佳的测试效果,应该由独立的第三方从事测试工作。
3.测试对象
软件测试并不等于程序测试。软件测试应贯穿于软件定义与开发的整个期间。
需求分析、概要设计、详细设计以及程序编码等各阶段所得到的文档,包括需求规格说明、概要设计规格说明、详细设计规格说明以及源程序,都应成为软件测试的对象。
4.测试方法
测试任何产品都有两种方法:黑盒测试和白盒测试。对于软件测试而言,黑盒测试法把程序看作一个黑盒子,完全不考虑程序的内部结构和处理过程。也就是说,黑盒测试是在程序接口进行的测试,它只检查程序功能是否能按照规格说明书的规定正常使用,程序是否能适当地接收输入数据并产生正确的输出信息,程序运行过程中能否保持外部信息(如数据库或文件)的完整性。黑盒测试又称为功能测试。
白盒测试法的前提是可以把程序看成装在一个透明的白盒子里,测试者完全知道程序的结构和处理算法。这种方法按照程序内部的逻辑测试程序,检测程序中的主要执行通路是否都能按预定要求正确工作。白盒测试又称为结构测试。
5.测试步骤
大型软件系统通常由若干个子系统组成,每个子系统又由许多模块组成,因此,大型软件系统的测试过程基本上由下述步骤组成。
(1)模块测试
在设计得好的软件系统中,每个模块完成一个清晰定义的子功能,而且这个子功能和同级其他模块的功能之间没有相互依赖关系。因此,有可能把每个模块作为一个单独的实体来测试。模块测试的目的是保证每个模块作为一个单元能正确运行,所以模块测试通常又称为单元测试。在这个测试步骤中所发现的往往是编码和详细设计的错误。
(2)子系统测试
子系统测试是把经过单元测试的模块放在一起形成一个子系统来测试。模块相互之间的通信接口是子系统测试的重点。
(3)系统测试
系统测试是把经过测试的子系统装配成一个完整的系统来测试。在这个测试步骤中发现的往往是软件设计中的错误,也可能发现需求说明中的错误。
(4)验收测试
验收测试将软件系统作为单一的实体进行测试,测试内容与系统测试基本类似,一般是在用户参与下进行测试。验收测试的目的是验证系统确实能够满足用户的需要。验收测试也称为确认测试。
测试作为软件工程的一个阶段,它的根本任务是保证软件的质量,因此除了进行测试之外,还有另外一些与测试密切相关的工作应该完成。
6.测试阶段的信息流
测试阶段的输入信息有两类:
(1)软件配置,包括需求说明书、设计说明书和源程序清单等。
(2)测试配置,包括测试计划和测试方案。所谓测试方案不仅仅是测试时使用的输入数据(称为测试用例),还应该包括每组输入数据预定要检验的功能,以及每组输入数据预期应该得到的正确输出。实际上测试配置是软件配置的一个子集,最终交出的软件配置应该包括上述测试配置以及测试的实际结果和调试的记录。
7.软件测试策略
一般的做法是,用黑盒法设计基本的测试方案,再利用白盒法补充一些必要的测试方案。所有测试过程都应采用综合测试策略,即先作静态分析,再作动态测试,并事先制订测试计划。具体地说,可用以下策略结合各种方法:
(1)在任何情况下都应该使用边界值分析的方法。
(2)必要时用等价划分法补充测试方案。
(3)必要时用错误推测法补充测试方案。
(4)如果在程序的功能说明中含有输入条件的组合,最好在一开始就用因果图法,然后再按以上三个步骤进行。
(5)对照程序逻辑,检查已设计出的设计方案。可以根据对程序可靠性的要求采用不同的逻辑覆盖标准,如果现有测试方案的逻辑覆盖程度没达到要求的覆盖标准,则应再补充一些测试方案。
(6)对于参数配置类的软件,要用正交试验法选择较少的组合方式达到最佳组合。
二、黑盒测试技术
黑盒测试着重测试软件功能。白盒测试在测试过程的早期阶段进行,而黑盒测试主要用于测试过程的后期。黑盒测试有多个方法,如等价类划分、边界值分析法、因果图法、决策表法、错误推测法、场景法等。下面对各个方法逐一进行介绍(场景法在本章第三节中结合列控系统测试进行介绍)。
(一)等价类划分定义
1.定义
等价类划分是把所有可能的输入数据,即程序的输入域划分成若干部分(子集),然后从每一个子集中选取少数具有代表性的数据作为测试用例。该方法是一种重要的、常用的黑盒测试用例设计方法。
2.划分等价类
等价类是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的,并合理地假定:测试某等价类的代表值就等于对这一类其他值的测试,因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件就可以用少量代表性的测试数据取得较好的测试结果。等价类划分可有两种不同的情况:有效等价类和无效等价类。
(1)有效等价类
有效等价类是指对于程序的规格说明来说是合理的、有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能。
(2)无效等价类
无效等价类与有效等价类的定义恰巧相反。无效等价类指对程序的规格说明是不合理的或无意义的输入数据所构成的集合。对于具体的问题,无效等价类至少应有一个,也可能有多个。
设计测试用例时,要同时考虑这两种等价类。因为软件不仅要能接收合理的数据,也要能经受意外的考验,这样的测试才能确保软件具有更高的可靠性。
3.划分等价类的标准
(1)整个集合是完备的,避免冗余。
(2)由集合划分出来的子集互不相交。
(3)同一类中标识(选择)一个测试用例,同一等价类中,往往处理相同,相同处理映射到“相同的执行路径”。
4.划分等价类的方法
(1)在输入条件规定了取值范围或值的个数的情况下,则可以确立一个有效等价类和两个无效等价类。
(2)在输入条件规定了输入值的集合或者规定了“必须如何”的条件的情况下,可确立一个有效等价类和一个无效等价类。
(3)在输入条件是一个布尔量的情况下,可确定一个有效等价类和一个无效等价类。
(4)如果规定了输入数据的一组值(假定n个),并且程序要对每一个输入值分别处理的情况下,可确立n个有效等价类和一个无效等价类。
(5)如果规定了输入数据必须遵循的规则,则可以确立一个有效等价类(符合规则)和若干个无效等价类(从各种不同角度违反规则)。
(6)在确知已划分的等价类中各元素在程序处理中的方式不同的情况下,则应再将该等价类进一步地划分为更小的等价类。
5.设计测试用例
在确立了等价类后,可建立等价类表,列出所有划分出的等价类输入条件:有效等价类、无效等价类,然后从划分出的等价类中按以下三个原则设计测试用例:
(1)为每一个等价类规定一个唯一的编号。
(2)设计一个新的测试用例,使其尽可能多地覆盖尚未被覆盖的有效等价类,重复这一步,直到所有的有效等价类都被覆盖为止。
(3)设计一个新的测试用例,使其仅覆盖一个尚未被覆盖的无效等价类,重复这一步,直到所有的无效等价类都被覆盖为止。
(二)边界值分析法
1.定义
边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。
2.与等价划分的区别
(1)边界值分析不是从某等价类中随便挑一个作为代表,而是使这个等价类的每个边界都要作为测试条件。
(2)边界值分析不仅考虑输入条件,还要考虑输出空间产生的测试情况。
3.边界值分析方法
长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。
使用边界值分析方法设计测试用例,首先应确定边界情况。通常输入和输出等价类的边界,就是应着重测试的边界情况。应当选取正好等于、刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。
通常设计测试方案总是联合使用等价划分和边界值分析两种技术。
通常情况下,软件测试所包含的边界检验有以下类型:数字、字符、位置、重量、大小、速度、方位、尺寸、空间等。相应的,以上类型的边界值应该在最大/最小、首位/末位、上/下、最快/最慢、最高/最低、最短/最长、空/满等情况下。
4.基于边界值分析方法选择测试用例的原则
(1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据。
(2)如果输入条件规定了值的个数,则用最大个数、最小个数、比最小个数少一、比最大个数多一的数作为测试数据。
(3)将上述两个原则应用于输出条件,即设计测试用例使输出值达到边界值及其左右的值。
(4)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例。
(5)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例。
(6)分析规格说明,找出其他可能的边界条件。
5.常见的边界值
(1)对16bit的整数而言,32767和-32768是边界。
(2)屏幕上光标在最左上、最右下位置。
(3)报表的第一行和最后一行。
(4)数组元素的第一个和最后一个。
(5)循环的第0次、第1次和倒数第2次、最后一次。
(三)因果图法
1.定义
因果图法是一种利用图解法分析输入的各种组合情况,从而设计测试用例的方法,它适合于检查程序输入条件的各种组合情况。
2.因果图法产生的背景
等价类划分法和边界值分析方法都是着重考虑输入条件,但没有考虑输入条件的各种组合、输入条件之间的相互制约关系。这样虽然各种输入条件可能出错的情况已经测试到了,但多个输入条件组合起来可能出错的情况却被忽视了。
如果在测试时必须考虑输入条件的各种组合,则可能的组合数目将是天文数字,因此必须考虑采用一种适合于描述多种条件的组合、相应产生多个动作的形式来进行测试用例的设计,这就需要利用因果图(逻辑模型)。
3.采用因果图法设计测试用例的步骤
(1)确定软件规格中的原因和结果。分析规格说明中哪些是原因(即输入条件或输入条件的等价类),哪些是结果(即输出条件),并给每个原因和结果赋予一个标识符。
(2)确定原因和结果之间的逻辑关系。分析软件规格说明中的语义,找出原因与结果之间、原因与原因之间对应的关系,根据这些关系画出因果图。
(3)确定因果图中的各个约束。由于语法或环境的限制,有些原因与原因之间、原因与结果之间的组合情况不可能出现。为表明这些特殊情况,在因果图上用一些记号表明约束或限制条件。
(4)把因果图转换为决策表。
(5)根据决策表设计测试用例。
(四)决策表法
1.定义
决策表是把作为条件的所有输入的各种组合值以及对应输出值都罗列出来而形成的表格。
2.决策表方法
在所有的黑盒测试方法中,基于决策表的测试是最严格、最具有逻辑性的测试方法。它能够将复杂的问题按照各种可能的情况全部列举出来,简明并且避免遗漏。因此,利用决策表能够设计出完整的测试用例集合。
决策表通常由条件桩、条件项、动作桩和动作项4部分组成。动作项和条件项紧密相关,指出在条件项的各组取值情况下应采取的动作。
3.决策表的构造及化简
构造决策表可采用以下5个步骤:
(1)列出所有的条件桩和动作桩;
(2)确定规则的个数;
(3)填入条件项;
(4)填入动作项,得到初始决策表;
(5)简化决策表,合并相似规则。
4.决策表的化简
对于n个条件的决策表,相应有2个规则(每个条件分别取真、假值),当n较大时,决策表很繁琐。实际使用决策表时,常常先将它简化。决策表的简化是以合并相似规则为目标。即若表中有两条以上规则具有相同的动作,并且在条件项之间存在极为相似的关系,便可以合并。
(五)错误推测法
错误推测法在很大程度上靠直觉和经验进行。它的基本想法是列举出程序中可能有的错误和容易发生错误的特殊情况,并且根据它们选择测试方案。
三、白盒测试技术
设计测试方案是测试阶段的关键技术问题。所谓测试方案包括具体的测试目的(例如,预定要测试的具体功能)、应该输入的测试数据和预期的结果。通常又把测试数据和预期的输出结果称为测试用例。其中最困难的问题是设计测试用的输入数据。
不同的测试数据发现程序错误的能力差别很大,为了提高测试效率降低测试成本,应该选用高效的测试数据。设计测试方案的基本目标是,确定一组最可能发现某个错误或某类错误的测试数据。
用白盒测试技术测试软件时设计测试数据的典型技术包括逻辑覆盖和控制结构测试。
遵循的原则如下:
(1)保证一个模块中所有独立路径至少被测试一次。
(2)所有逻辑值均需测试真(true)和假(false)两种情况。
(3)检查程序的内部数据结构,保证其结构的有效性。
(4)在上下边界及可操作范围内运行所有循环。
(一)逻辑覆盖
有选择地执行程序中某些最有代表性的通路是对穷尽测试的唯一可行的替代办法。从覆盖源程序语句的详尽程度分析,大致有以下一些不同的覆盖标准。
1.语句覆盖
语句覆盖的含义是,选择足够多的测试数据,使被测程序中每个语句至少执行一次。
2.判定覆盖
判定覆盖又叫分支覆盖,它的含义是,不仅每个语句必须至少执行一次,而且每个判定的每种可能的结果都应该至少执行一次,也就是每个判定的每个分支都至少执行一次。
3.条件覆盖
条件覆盖的含义是,不仅每个语句至少执行一次,而且使判定表达式中的每个条件都取到各种可能的结果。
4.判定/条件覆盖
判定/条件覆盖的含义是,选取足够多的测试数据,使得判定表达式中的每个条件都取到各种可能的值,而且每个判定表达式也都取到各种可能的结果。
5.条件组合覆盖
条件组合覆盖是更强多逻辑覆盖标准,它要求选取足够多的测试数据,使得每个判定表达式中条件的各种可能组合都至少出现一次。
从对程序路径的覆盖程度分析,能够提出下述一些主要的逻辑覆盖标准。
(1)点覆盖;
(2)边覆盖;
(3)路径覆盖。
(二)控制结构测试
1.基本路径测试
基本路径测试是Tom McCabe提出的一种白盒测试技术。使用这种技术设计测试用例时,首先计算程序的环形复杂度,并据此定义执行路径的基本集合,从该基本集合导出的测试用例可以保证程序中的每条语句至少执行一次,而且每个条件在执行时都将分别取真、假两种值。
使用基本路径测试技术设计测试用例的步骤如下:
(1)根据过程设计结果画出相应的流图
流图实质上是“退化了的”程序流程图,它仅仅描绘程序的控制流程,完全不表现对数据的具体操作以及分支或循环的具体条件。
在流图中用圆表示结点,一个圆代表一条或多条语句。流图中的箭头线称为边,代表控制流。由边和结点围成的面积称为区域。
(2)计算流图的环形复杂度
环形复杂度度量程序的逻辑复杂度,有3种计算方法。
①流图中的区域数等于环形复杂度。
②流图G的环形复杂度V(G)=E-N+2,其中,E是流图中边的条数,N是结点数。
③流图G的环形复杂度V(G)=P+1,其中,P是流图中判定结点的数目。
(3)确定线性独立路径的基本集合
独立路径至少包含一条在定义该路径之前不曾用过的边。程序的环形复杂度决定了程序中独立路径的数量,而且这个数是确保程序中所有语句至少被执行一次所需的测试数量的上界。
(4)设计可强制执行基本集合中每条路径的测试案例
应该选取测试数据使得在测试每条路径时都适当地设置好了各个判定结点的条件。
在测试过程中,执行每个测试用例并把实际输出结果与预期结果相比较。一旦执行完所有测试用例,就可以确保程序中所有语句都至少被执行了一次,而且每个条件都分别取过True值和False值。
2.条件测试
用条件测试技术设计出的测试用例,能够检查程序模块中包含的逻辑条件。条件测试的目的不仅是检测程序条件中的错误,而且是检测程序中的其他错误。
一个简单条件是一个布尔变量或一个关系表达式,在布尔变量或关系表达式之前还可能有一个NOT算符。
分支测试可能是最简单的条件测试策略:对于复合条件C来说,C的真分支和假分支以及C中的每个简单条件,都应该至少执行一次。
3.循环测试
循环测试专注于测试循环结构的有效性,在结构化的程序中通常只有3种循环,即简单循环、串接循环和嵌套循环。
四、测试案例
测试案例的好坏直接关系到测试结果的可信度,而测试结果又对软件评价起着至关重要的作用。安全软件的测试结果经对比或判定可分为三大类:
(1)正确结果,即与需求规格说明或期望的属性相一致。
(2)故障导向安全的结果,与用户的期望有差异,但在出现不正确结果的同时能使系统维持在安全状态。
(3)失效,结果不仅不正确,而且产生了危险输出。