第一章 软件质量和软件测试概述
1.1 软件质量
1.1.1 质量概念
质量的定义:
质量是反映实体满足明确或隐含需求能力的特征和特征的总和。
1.1.2 软件及软件质量概念
IEEE关于软件质量的定义是:
系统、部件或过程满足需求的程度;系统、部件或过程满足顾客或用户需求或期望的程度 。
ISO/IEC 25010中定义的软件产品质量模型包括下列八个质量特性:
1. 功能适应性
特征:完整性、正确性、恰当性
2. 性能效率
特征:时间特性、资源利用率、容量
3. 兼容性
特征:共存性、互操作性
4. 易用性
特征:适当的可识别性、易学性、易操作性、用户错误保护、用户界面美光度、可达性
5. 可靠性
特征:成熟性、可用性、容错性、可恢复性
6. 安全性
特征:保密性、完整性、不可否认性、可核查性、真实性
7. 可维护性
特征:模块化、可复用性、易分析性、易修改性、易测试性
8. 可移植性
特征:适应性、可安装性、可替换性
1.2 软件测试
1.2.1 软件测试的意义
1. 意义
软件测试是评估软件质量和降低软件运行出现失效风险的一种方法。
2. 区分软件错误、缺陷、失效这三个概念
软件错误:指在软件生存期内的不希望或不可接受的人为错误,其结果是导致软件缺陷的产生。
软件缺陷:为计算机软件或程序中存在的某种破坏正常运行能力的问题、错误或者隐藏的功能缺陷。
软件失效:指软件运行时产生 的一种不希望或不可接受的外部行为结果。
1.2.2 软件测试的定义
软件测试的定义:
使用人工或自动手段来运行或测定某个系统的过程,其目的在于检测它是否满足规定的需求或者是否弄清预期结果与实际结果之间的差别。测试是对程序或系统能否完成特定任务建立信心的过程。软件测试是说明程序是否正确的最基本的一种技术手段。
测试和调试的区别:
测试是发现由于软件缺陷引起的失效,调试是发现、分析和修复这些缺陷的开发活动。
1.2.3 软件测试的方法
1. 根据测试时是否运行被测体,可分为动态测试和静态测试。
2. 根据测试时是否查看程序内部结构或者按被测体可见与否,可分为白盒测试和黑盒测试。
第二章 软件质量标准
2.1 CMMI标准
CMMI(Capability Maturity Model Integration,能力成熟度模型集成)是用于产品开发(或服务)的过程改进成熟度模型
第三章 软件全面质量管理
第四章 软件质量保证
第五章 软件测试基础
5.1 目的和原则
5.1.1 目的
1. 好的测试方案是极其可能发现迄今为止尚未发现的错误的测试方案。
2. 成功的测试是发现了至今为止尚未发现的错误的测试。
3. 测试分析能帮助测试人员设计出有针对性的测试方法,改善测试的效率和有效性。
5.1.2 原则
1.测试说明缺陷的存在,而不能说明缺陷不存在。
2.穷尽测试是不可能的。
3.测试的尽早介入可以节省时间和成本。
4.缺陷的群集效应。
5.杀虫剂悖论。
6.测试活动依赖于测试内容和情景。
7.不存在缺陷的谬论。
5.2 测试过程
软件测试过程与软件开发流程类似,也包括计划、设计、开发、执行和评估5个阶段。
在需求分析和应用设计阶段就应开始进行测试工作,编写相应的测试计划及测试设计文档。
5.2.1 测试计划
测试计划:确定测试范围和任务、确定测试方法和方式、确定测试环境与辅助工具、确定测试通过标准、确定测试人员和任务表、确定测试相关规范和约定。
测试计划的工作产品:通常包括一个或多个测试计划,测试计划包括关于测试依据与其他测试工作产品之间可追溯性的相关信息。
第六章 软件生命周期的测试
6.1 软件测试模型
最常见的软件测试模型有V模型、W模型、H模型、X模型和前置测试模型。
6.1.1 V模型
V模型是基于瀑布模型的,V模型描述了基本的开发过程和测试行为。
软件测试的V模型以“编码”为黄金分割线,将整个过程分为开发和测试,并且开发和测试之间是串行的关系。
优点:
V模型清楚的标识了开发和测试的各个阶段,每个阶段分工明确,便于整体项目的把控。
缺点:
V模型有一个缺点,就是将测试放在整个开发的最后阶段,没有让测试尽早介入开发,没有在需求阶段就引入测试,忽视了测试活动对需求分析、系统设计等开发活动的验证和确认功能。
6.1.2 W模型
软件测试的W模型由Evolutif公司提出,W模型是V模型的发展。
W模型是由两个V模型组成的,一个是开发阶段,一个测试阶段。
在W模型中开发和测试是并行的关系。
优点:
测试与开发并行,让测试尽早介入开发环节,使测试尽早发现问题尽早解决。
开发阶段的测试有利于及时了解项目的难度、设计结构和代码结构,及早识别测试风险,及早制定应对措施。
缺点:
在整个开发阶段,仍然是串行的,上一阶段未完全完成无法进入下一阶段,不支持敏捷模式的开发。
开发和测试的线性关系导致需求变更的不便。如果没有文档,根本无法执行W模型。
对整个项目组成员的技术要求更高。
6.1.3 H模型
H模型中,软件测试过程活动完全独立,贯穿于整个产品的周期,与其他流程并发地进行,某个测试点准备就绪时,就可以从测试准备阶段进行到测试执行阶段。软件测试可以尽早的进行,并且可以根据被测对象的不同而分层次进行。
H模型对管理、技能及整个项目组的人员要求都很高。
管理方面,由于模型很灵活,必须要定义清晰的规则和管理制度,否则测试过程将非常难以管理和控制。
技能上,H模型要求能够很好的定义每个迭代的规模,不能太大也不能太小。
6.1.4 X模型
X模型的基本思想是由Marick 提出的,Robin F Goldsmith引用了Marick 的一些想法并经过重新组织形成了“X模型”。
优点:
X模型还引入了探索性测试;
呈现了一种动态测试的过程,测试处于一个不断迭代的过程中
6.1.5 前置测试模型
前置测试模型的特点:
1. 开发和测试相结合
2. 对每一个交付内容进行测试
3. 在设计阶段进行计划和测试设计
4. 测试和开发结合在一起
5. 让验收测试和技术测试保持相互独立
6.2 测试级别
测试级别是一组共同组织和管理的测试活动。
主要的测试级别有:
组件测试、集成测试、系统测试和验收测试。
6.2.1 组件测试
组件测试(Unit Testing)是指对软件中的最小可测试组 件或基本组成组件进行检查和验证。
组件测试可以包括功能、非功能特性和结构特性的测试。
辅助测试模块有两种:
驱动模块和桩模块。
1.驱动模块(Drive)
驱动模块用来模拟被测试模块的上一级模块,相当于被 测模块的主程序。它接收数据,将相关数据传送给被测模块,启动被测模块,并打印出相应的结果。
2.桩模块(Stub)
桩模块用来模拟被测模块工作过程中所调用的模块。它们一般只进行很少的数据处理。
6.2.2 集成测试
集成测试是在组件测试的基础上,将所有已通过组件测试 的模块按照概要设计的要求组装成子系统或系统,进行集成测试,目的是确保各单元模块组合在一起后能够按既定意图协作运行。
两种不同级别的集成测试:
1. 组件集成测试,侧重于集成组件之间的交互和接口。
2. 系统集成测试,侧重于系统、软件包和微服务之间的交互和接口。
集成测试策略分为非增量式测试和增量式测试两种。
以如图6.8所示的程序结构为被测程序,由A、B、C、D、E、F六个模块组成。接下来详细介绍不同集成策略的集成测试过程。
1.非增量式测试
非增量式测试是采用一步到位的方法来构建测试的。对所有模块进行个别的组件测试后,按照程序结构图将各模块连接起来, 把连接后的程序当作一个整体进行测试。
如图所示,B和D两个模块位于中间层次,需要配置驱动模块和桩模块,分别为d1和d3,s1和s2;C、E、F三个模块位于最底层需要配置驱动模块,分别为d2、d4和d5;A模块位于最顶层,不被任何模块调用,一级库程序机构配置桩模块s3、s4、s5,模拟A模块调用的B、C和D三个模块。完成组件测试后,最后一局程序结构连接起来,进行集成测试。
优点:
可并行调试所有模块,充分利用人力、资源、加快进度。
缺点:
1. 不能对各模块的接口进行充分测试,易漏掉潜在接口错误。
2. 不能很好地对全局数据结构进行测试。
3. 集成模块过多会出现大量错误,难以定位修改,往往需经多次测试才能运行成功。
总结:
这种测试策略适用于只需修改或增加少数几个模块的前期产品稳定的项目。
2.增量式测试
增量式测试的集成是逐步实现的。逐次将未曾集成测试的模块和已经集成测试的模块(或子系统)结合成程序包,再将这些模 块集成为较大系统,在集成的过程中边连接边测试,以发现连接过程中产生的问题
(1)自顶向下增量式测试
广度优先方式的集成,首先沿着水平方向,把每一层中所有直接隶属于上一层的模块集成起来,直到底层。
深度优先方式的集成,首先集成在结构中的一个主控路径下的所有模块,主控路径的选择是任意的。
(2)自底向上增量式测试
自底向上增量式测试表示逐步集成和逐步测试的工作是按结构图自下而上进行的,即从程序模块结构的最底层模块开始集成和测试。
(3)混合增量式测试
混合增量式测试是把自顶向下测试和自底向上测试这两种方式结合起来进行集成和测试的。
第七章 软件静态测试技术
7.1 静态测试和测试过程
静态测试是指不运行被测程序本身,仅通过分析或检查源程序的语法、结构、过程、接口等来检查程序的正确性。它可以由人工进行,充分发挥人的逻辑思维优势,也可以借助测试工具进行。静态测试结果可用于进一步的查错,并为测试用例选取提供指导。
优点:
发现缺陷早、降低返工成本、覆盖重点和发现缺陷的概率高等
缺点:
耗时⻓、不能测试依赖和技术能力要求高。
7.1.1 静态测试的基本内容
静态测试主要包括各阶段的评审、代码检查、静态结构分析、软件静态质量度量等,用于对被测程序进行特性分析。
7.1.2 静态测试的过程
理论上,静态测试应从项目立项即开始测试,然后始终贯穿整个项目。但在实际操作过程中,基本上是上一个版本系统测试结束的时候才进入下一个版本的静态测试阶段。
1.熟悉业务流程和背景
2.准备好产品说明书
3.审查和测试同类软件
7.1.3 控制流分析
控制流分析(Control flow analysis,CFA)是一类用于分析程序控制流结构的静态分析技术
目的在于生成程序的控制流图,在编译器设计、程序分析、程序理解等领域都有重要应用。对程序的控制流分析是对源程序或者源程序的中间表示形式的直接操作,形成控制流图。
1. 程序控制流分析
程序控制流是指程序(组件或单元)或系统中的一系列顺序发生的事件或路径。
控制流分析从程序的特点上看,可以将其看作两个大类:过程内的控制流分析和过程间的控制流分析。
2. 程序控制流图
控制流图(Control Flow Graph,CFG)也叫控制流程图, 是一个过程或程序的抽象表现,是用在编译器中的一个抽象数据结构,由编译器在内部维护,代表了一个程序执行过程中会遍历到的所有路径。
描绘了测试对象的程序逻辑控制结构。控制流图由过程块、决策点、控制流线和汇聚点4个元素构成。
-过程块(也称结点),是从开始到结束按照顺序执行的一系列程序语句或代码,除了在开始处没有其他入口可进入。同样,在结束处没有其他出口可离开过 程块(结点)。
-决策点,指的是测试对象中的一个点,在此点上控制流线选择的方向发生变化。决策点一般是以分支形式存在。决策点是以一个圆圈、一个入口和多个出口点表示的。包含条件的结点称为判定结点。
-汇聚点,指测试对象中的一个点,但与决策点相反,在汇聚点上不同流的选择方向在此汇聚。
-域,由边和结点限定的区域称为域。
3. 控制流分析的测试运用
(1)独立程序路径和基本路径集合
独立路径是任何贯穿程序的、至少引入一组新语句(处理语句或条件语句)的路径。
图(b)所示的程序控制流图的一组独立路径如下:
路径1 :1-11
路径2 :1-2-3-4-5-10-1-11
路径3 :1-2-3-6-8-9-10-1-11
路径4 :1-2-3-6-7-9-10-1-11
路径1、2、3、4构成流图的基本路径集合(称为基本集合)。
(2)控制流分析的测试运用
常常使用环形复杂度来度量软件复杂度,环形复杂度值越大,则程序复杂度越高。
环形复杂性(或称圈复杂性)是一种软件度量,它为程序的逻辑复杂性提供了一个量化测度。当测试运用基本路径测试方法时,环形复杂性的值定义了程序基本集合中的独立路径数,并提供了保证所有语句至少执行一次所需测试数量的上限。
环形复杂度,记录为V(G),它用来衡量一个程序模块所包含的判定结构的复杂程度,数量上表现为独立路径的条数,即合理地预防错误所需测试的最少路径条数,圈复杂度大的程序,说明其代码可能质量低且难于测试和维护。经验表明,程序可能存在的Bug数和圈复杂度有着很大的相关性。
环形复杂度的计算公式为:
V(G) = E-N+2 E表示控制流图中边的数量 N表示控制流图中结点的数量
V(G) = 区域数 = 判定节点数+1
圈复杂度所反映的是“判定条件”的数量,所以圈复杂度实际上就是等于判定节点(决策点)的数量再加上1,也即控制流图的区域数。
V(G) = 区域数字
环形复杂度的计算:
V(G) = E-N+2 = 11-9+2 = 4
V(G) = 区域数 = 判定节点数+1 = 3+1 = 4
V(G) = 区域数 = 4
7.1.4 数据流分析
1.数据流分析的相关概念
数据流指的是数据对象的顺序和可能状态的抽象表示。
数据对象的状态可以是创建/定义(Creation/Defined)、使用 (Use)和清除/销(Killed/Destruction)。
数据流测试用作路径测试的“真实性检查”,包括“定义/使用”测试和 “基于程序片”的测试两种形式。
2.定义/使用测试
程序数据流图
程序数据流图的构造方式同控制流图,节点是语句或语句的一部分,边表示语句的控制流程;单出口,且不允许从某个节点到其自身的边。其中:
G(P)为程序数据流图;
P代表程序;
V表示一组程序变量,即变量集合;
P的所有路径集合为PATH(P)。
某片段程序如下,对其进行数据流分析,写出变量a的定义-使用路径(du-path),并判断是否定义-清除路径(du-path)。
a=5; //定义a
While(C1) {
if(C2){
b = a*a; //使用a
a = a-1; //定义且使用a
}
print(a); //使用a
}
以上程序对应的程序数据流图,如左侧图所示。根据程序的数据“定义-使用”对,找出所有的“定义-使用”路经,可得到变量a和b的定义-使用节点,变量a的定义-使用路径及其是否为定义-清除路径,如下表所示:
第八章 软件测试技术
8.1 黑盒测试技术
黑盒测试技术(也称为行为的或基于规格说明的技术)基于对测试依据的分析(例如:正式需求文档、说明、用例、用户故事或业务流程)。这些技术适用于功能和非功能测试。黑盒测试技术关注在测试对象的输入和输出,而不考虑其内部结构。
8.1.1 等价类划分法
等价类测试方法是把所有可能的输入数据,即程序的输入域划分成若干部分,然后从每一部分中选取少数有代表性的数据作为测试用例。
若 (A,B) 是命题 f(x) 的一个等价区间,在 (A,B) 中任意取xi 进行测试。如果 f(xi) 错误,那么 f(x) 在整个 (A,B) 区间都将 出错;如果 f(xi) 正确,那么 f(x) 在整个(A,B) 区间都将正确。
等价类划分可有两种不同的情况:有效等价类和无效等价类。
有效等价类:对于程序的需求规格说明来说是合理的,有意义的输入数据构成的集合。利用有效等价类可检验程序是否实现了规格说明中所规定的功能和性能(确认过程)。
无效等价类:对于程序的需求规格说明来说是不合理的,无意义的输入数据构成的集合。利用无效等价类可检验程序对于无效数据的异常处理能力(检验过程)。
例如,某参数值输入值的有效范围:1000~1500
有效等价类:{1000< = 参数值 < = 1500}
无效等价类:{参数值 < 1000.00},{ 参数值 > 1500.00}
有效等价类,至少要有一个,无效等价类可以有若干个
(1)标准等价类测试:不考虑无效数据值,测试用例使用每个等价类中的某一个值 (如左图所示)。通常标准等价类测试用例数量和最大等价类中元素数目相等。
(2)健壮等价类测试:主要出发点是不仅关注等价类,同时也关注无效等价类。对有效输入,测试用例从每个有效等价类中取一个值;对无效输入,测试用例取一个无效值,其他值均取有效值。
健壮等价类测试需注意,规格说明往往没有定义无效测试用例的期望输出应该是什么。因此,需定义这些测试用例的期望值。
等价类划分测试用例设计步骤
(1)划分等价类后,建立等价类表,并为每一个等价类规定一个唯一的编号;
(2)设计一个测试用例,使其尽可能多地覆盖尚未被覆盖地有效等价类,重复这一步骤,直到所有的有效等价类都被覆盖为止;
(3)设计一个新的测试用例,使其仅覆盖一个尚未被覆盖的无效等价类,重复这一步骤,直到所有的无效等价类都被覆盖为止。(因为用单个测试用例覆盖无效等价类,是因为某些特定的输入错误会屏蔽或取代其他输入错误检查)。
测试前定义覆盖率作为测试活动是否充分标准及测试执行后判断测试强度是否达到要求的一个指标。
等价类划分覆盖率=(执行的等价类数量/总共划分确定的等价类数量)×100%
8.1.2 边界值分析法
采用二值还是三值测试法取决于被测项的⻛险大小。⻛险高的采用三值测试法。
通常边界值分析法是作为等价类划分法的补充,测试用例来自等价类的边界。
例如:三⻆形组成问题描述中,要求边⻓为正整数,其输入域边界下限值为1, 上限值为100。其中 1、2、99、100为边界值。
测试用例 | a | b | c | 预期输出 |
test1 | 50 | 50 | 1 |
等腰三角形 |
test2 | 50 | 100 | 50 | 非三角形 |
test3 | 50 | 50 | 2 | 等腰三角形 |
test4 | 50 | 50 | 99 | 等腰三角形 |
test5 | 50 | 50 | 50 | 等边三角形 |
边界值分析法与等价类分析法的区别
边界值分析法与等价类划分的区别在于:边界值分析不是从某等价类中随便挑一个作为代表,而是使这个等价类的每个边界都要作为测试条件。
边界值覆盖率=(执行的边界值数量/总的边界值数量)×100%
8.1.3 决策表测试
8.1.4 基于状态的测试
8.1.5 基于用例的测试
8.1.6 基于用户故事(敏捷开发)的测试
8.2 白盒测试技术
白盒测试技术(也称为结构的或基于结构的技术)基于对架构、详细设计、内部结构或测试对象代码的分析来产生或选择测试用例。
与黑盒测试技术不同,白盒测试技术关注在测试对象的结构和处理过程。白盒测试是基于测试对象的内部结构的测试技术。
8.2.1 白盒测试的实施步骤
1. 测试计划阶段:根据需求说明书,制定测试进度。
2. 测试设计阶段:依据程序设计说明书,按照一定规范化的方法进行软件结构划分和设计测试用例。
3. 测试执行阶段:输入测试用例,得到测试结果。
4. 测试总结阶段:对比测试的结果和代码的预期结果,分析错误原因,找到并解决错误。
白盒测试技术可以应用在所有测试级别。
8.2.2 语句覆盖及其覆盖率
语句覆盖(Statement Coverage)的测试目标是运行若干测试用例,使被测试的程序的每一条可执行语句至少执行一次。这里所谓“若干个”,自然是越少越好。测试主要集中在测试对象语句上。用例执行需满足事先定义的最小数目或所有语句。如要求覆盖所有语句而有些语句任何测试用例都无法覆盖,则出现不可达代码语句覆盖第一步是将源代码转换为控制流图。控制流图中节点是覆盖关注点。
设计一个能通过路径 acef 的测试路径即可实现语句覆盖。
当 A=2, B=0, X=3 时,程序按流程图上路径 ace(流图上路径BCEF或1-2- 3-4-5)执行,即程序段中4语句均得到执行,完成语句覆盖。
优点:
很直观地从代码中得到测试用例,无需细分每条判定表达式。
缺点:
对于隐藏的条件和可能到达的隐式分支是无法测试的。它只运行一次,而不考虑其他情况。
测试完成准则定义:满足语句覆盖率。覆盖率以测试执行的语句数除以测试对象中可执行语句的总数来衡量,通常以百分比表示。
语句覆盖率 = (被执行语句的数量/所有语句数量)×100%
8.2.3 判定覆盖及其覆盖率
判定覆盖(又称为分支覆盖)测试基于判定结果执行的代码。要做到这一点,测试用例遵循从判定点触发的控制流(例如:对于IF语句,一个用于真的结果,一个用于假的结果;对于一个CASE语句,所有可能的结果都需要测试用例,包括默认结果)。
分支覆盖是比语句覆盖强的覆盖测试。通过执行测试用例,使程序每个 判定至少都获得一次“真”值和“假”值,即要使程序中每个取“真”分支和 取“假”分支至少均经历一次。
对示例,设计两测试用例,使通过路径 ace 和 abd(流图上路径AD或1-3- 5),或通过路径acd(BCD或1-2-3-5)及 abe(AEF 或1-3-4-5),即可 达分支覆盖标准。 若选用的两组测试用例如表8.20所示,则可分别执行路径ace和 abd,使两判 断4分支 c,e 和 b,d 分别得到覆盖。
测试用例 | A,B,X | (A>1)AND(B=0) | (A=2)OR(X>1) | 执行路径 |
测试用例1 | 2 0 3 | 真(T) | 真(T) | ace(BCEF) |
测试用例2 | 1 0 1 | 假(-T) | 假(-T) | abd(AD) |
另一种情形:若选用的两组测试用例如表所示,则可分别执行流程图上路径 ace(流图路径BCD或1-2-3-5)及 abe(流图上AEF或1-3-4-5),可达到 对4个分支覆盖。
测试用例 | A,B,X | (A>1)AND(B=0) | (A=2)OR(X>1) | 执行路径 |
测试用例3 | 3 0 3 | 真(T) | 假(-T) | ace(BCD) |
测试用例4 | 2 1 1 | 假(-T) | 真(T) | abd(AEF) |
优点:
判定覆盖是比语句覆盖更强的测试能力,比语句覆盖要多几乎一倍的测试路径。它无需细分每个判定就可以得到测试用例。
缺点:
大部分的判定语句是由多个逻辑条件组合而成,若仅仅判断其最终结果, 而忽略每个条件的取值必然会遗漏部分的测试路径。
判定覆盖率 = (过测试执行的判定结果的数量/测试对象中判定结果的总数)×100%
8.2.4 条件覆盖及其覆盖率
判定是由逻辑运算符连接的几个条件确定的,则测试中需考虑条件复杂性、条件 组合时的不同需求和相应测试强度。
(1)分支条件测试
运行被测程序使程序中每个判断的每个条件所有可能值至少执行一次,并每个可能的判断结果也至少执行一次,即要求各个判断的所有可能的条件取值组合至少 执行一次。 分支条件测试目标是每个原子条件都需取到“真”、“假”两值。在测试对象源代码 中,一个条件可包含多个原子条件。
示例程序若采用测试用例1、5,就可达到分支条件测试,如表所示。
测试用例 | A,B,X | (A>1)AND(B=0) | (A=2)OR(X>1) | 执行路径 | 覆盖条件 |
测试用例1 | 2 0 3 | 真(T) | 真(T) | ace | T1,T2,T3,T4 |
测试用例5 | 1 1 1 | 假(-T) | 假(-T) | abd | -T1,-T2,-T3,-T4 |
(2)条件组合覆盖
在极少数情况下,可能需要测试所有可能的判定内所包含的真/假数值组合。这种穷尽级别的测试被称作条件组合覆盖,也称为C2覆盖。所需的测试数目依赖于判定语句中的原子条件个数,同时该测试数目可以由计算2n来确定,n是未重叠的 原子条件个数。运用之前提及的相同例子,需要以下测试来实现条件组合覆盖。
8.2.5 路径测试
虽然有的覆盖准则提到经历路径这一问题,但并未涉及路径的覆盖。路径能否被全面覆盖是测试重要问题。因程序要得到正确结果就必须能保证程序总是沿着特定路径顺利执行。
当程序中每条路径都经受检验才能使程序受到全面检验。任何有关路径分析的测试都可称路径测试。
路径测试是从程序入口开始执行所经历各语句的完整过程。它基于结构的测试, 完成路径测试的理想状况是做到路径完全被覆盖。
对较简单程序实现完全路径测试可行,但对程序中出现较多判定和较多循环则路径数目将会急剧增加,可能为一庞大数字,测试覆盖这样多的路径有时无法实现。
路径测试须遵循以下原则才能达测试目的:
1. 保证一个模块中的所有独立路径至少被测试过一次。
2. 所有逻辑值均需测试真(True)、假(False)两种情况。
3. 测试将检查程序的内部数据结构,并保证其结构的有效性。
4. 在取值的上下边界处,即在可操作范围内运行所有的循环。
为满足路径覆盖须首先确定具体路径及路径个数。下面给出路径更为概括的表示方法及路径计算。定义如下规则:
(1)弧a,b相乘,表示为ab。表明路径先经历弧a,再经历弧b,弧a和弧b先 后相接。
(2)弧a和弧b相加,表示为 a+b。表明两弧“或”关系,是并行路径。在图中,节点2和节点3有两弧相连(弧b和弧c)是并行的;弧d和弧e也为并行。 控制流中,共4条路经(abdf、abef、acdf、acef),可用加法连接,得整个路径:abdf+abef+acdf+acef。
(3)在路径表达式中,将所有弧均以数值1代替,再进行表达式的相乘和相加运算,最后得到数值为该程序路径数。程序中 所含路径数和程序复杂程度直接关联,即程序越复杂其所包含路径数就越多。
尽管如此,如果将无限循环的问题放置一边,实行路径测试还是现实的。为了应用这种技术,建议沿着软件模块的入口到出口的尽可能多的路径去创建测试用例。为了简化这个可能复杂的任务,可以通过使用以下流程来系统化地实现路径测试:
(1)先挑选从入口到出口最简单的、有意义的功能的路径。
(2)挑选每条额外的路径作为之前路径的微小变异。对于每个后续的测试,每个路径中尽可能只改变一个分支。尽可能优先选择短的路径而不是⻓的路径。 尽可能优先选择那些更有意义的功能路径,而不是无意义的功能路径。
(3)仅仅当要求满足覆盖率的时候,挑选那些无意义的功能路径。这样的路径可能是不相关的且应该受到质疑的。
(4)运用直觉来选择路径(也就是说,哪条路径是最可能被执行到的)。 注意,使用这种策略,可能会重复执行某些路径段。这个策略的关键点是代码中 每个可能的分支至少测试过一次,也可能多次。
优点:
路径覆盖是经常要用到的测试覆盖方法,它比普通的判定覆盖准则和条件覆盖准则覆盖率都要高。该方法适用于局部路径测试,如上述定义,往往会使用在安全关键软件中。
缺点:
虽然有可能使用控制流程图来确定路径,在现实中还是需要利用工具对复杂模块的路径进行计算。该方法创建足够的测试来覆盖所有路径(不考虑循环),这也已经保证达到了语句和分支覆盖。与分支测试相比较,路径测试仅增加相对少的测试数目,却提供了更彻底的测试。
8.2.6 基本路径测试
基本路径测试用例设计步骤如下:
1. 绘制程序控制流图
2. 通过分析环形复杂性,计算圈复杂度,导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。给定流图的圈复杂度V(G), 定义为V(G)= P + 1,P是流图G中判断结点的个数,如图所示。
3. 导出测试用例:根据环形复杂性和程序结构设计用例数据输入和预期结果。
4. 准备测试用例:确保基本路径集中的每一条路径的执行。
例题:利用基本路径测试方法测试下面的程序。
1. 请画出流图
2. 计算环路复杂度
3. 写出测试路径、设计测试用例
#include<iostream>
void add(int i,int j,int k, int m)
{
int s = 100;
if (i<9)
{
if ((j>5)&&(k<9))
{
s = s+1;
}
else
if ((i == 6)||(m>3))
{
s = s+3;
}
else
s = s+2;
}
else
s = s-1;
}
1. 流图如图所示:
2. 计算环路复杂度:
V(G)=3+1=4
3. 测试路径及测试用例如表所示。
测试用例 | i,j,k,m | 执行路径 |
测试用例1 | 10,6,6,6 | 2、17、18 |
测试用例2 | 8,6,8,4 | 2、4、6、18 |
测试用例3 | 6,6,10,4 | 2、4、9、11、18 |
测试用例4 | 8,5,10,2 | 2、4、9、14、18 |