1、教学目标教学目标理论环节理论环节 学习理解白盒测试方法的基本概念学习理解白盒测试方法的基本概念 学习理解白盒测试的覆盖理论学习理解白盒测试的覆盖理论 学习掌握白盒测试的路径表达学习掌握白盒测试的路径表达 学习掌握白盒测试的基本路径测试法学习掌握白盒测试的基本路径测试法实践环节实践环节 通过案例运用学习掌握覆盖问题的解决方法通过案例运用学习掌握覆盖问题的解决方法 运用基本路径测试方法进行实际程序测试运用基本路径测试方法进行实际程序测试 白盒测试也称结构测试或逻辑驱动测试,白盒测试也称结构测试或逻辑驱动测试,是针对被测单元内部是如何进行是针对被测单元内部是如何进行工作工作的测试。的测试。白盒法把测
2、试对象看做是一个打开的盒子,允白盒法把测试对象看做是一个打开的盒子,允许测试人员利用程序内部的逻辑结构及有关信许测试人员利用程序内部的逻辑结构及有关信息,设计或选择息,设计或选择测试用例测试用例,对程序所有逻辑路,对程序所有逻辑路径进行测试。通过在不同点检查程序的状态,径进行测试。通过在不同点检查程序的状态,确定实际的状态是否与预期的状态一致。确定实际的状态是否与预期的状态一致。白盒法也不可能进行穷举测试,企图遍历所有的路径,往往是做不到的。左图所示的一个小程左图所示的一个小程序的控制流程,其中每个序的控制流程,其中每个圆圈代表一段源程序(或圆圈代表一段源程序(或语句块),图中的曲线代语句块)
3、,图中的曲线代表执行次数不超过表执行次数不超过20的循的循环,循环体中共有环,循环体中共有5条通路。条通路。这样,可能执行的路径有这样,可能执行的路径有520条,近似为条,近似为1014条可能条可能的路径。如果完成一个路的路径。如果完成一个路径的测试需要径的测试需要1毫秒,那么毫秒,那么整个测试过程需要整个测试过程需要3170年。年。显然,这也是不能接受的。显然,这也是不能接受的。白盒法需要了解程序的内部结构和详细的处白盒法需要了解程序的内部结构和详细的处理过程,它按照程序内部逻辑测试程序,检理过程,它按照程序内部逻辑测试程序,检验程序中每条通路是否按预定要求正确工作。验程序中每条通路是否按预
4、定要求正确工作。对于白盒测试,即使每条路径都测试了,程序仍对于白盒测试,即使每条路径都测试了,程序仍可能有错。再如由于疏忽漏写了路径,白盒测试也发可能有错。再如由于疏忽漏写了路径,白盒测试也发现不了。现不了。所以,白盒法不能使测试达到彻底。为了用有限所以,白盒法不能使测试达到彻底。为了用有限的测试发现更多的错误,需精心设计测试用例。黑盒的测试发现更多的错误,需精心设计测试用例。黑盒法、白盒法是设计测试用例的基本策略,每一种方法法、白盒法是设计测试用例的基本策略,每一种方法对应着多种设计测试用例的技术,每种技术可达到一对应着多种设计测试用例的技术,每种技术可达到一定的软件质量标准要定的软件质量标
5、准要求。求。测试用例的设计白盒技术白盒技术 在测试阶段穷举测试不可行,必须要从在测试阶段穷举测试不可行,必须要从数量极大的可用测试用例中精心地挑选少量的数量极大的可用测试用例中精心地挑选少量的测试数据,使得采用这些测试数据能够达到最测试数据,使得采用这些测试数据能够达到最佳的测试效果,能够高效率地把隐藏的错误揭佳的测试效果,能够高效率地把隐藏的错误揭露出来。下面介绍几种白盒测试设计测试用例露出来。下面介绍几种白盒测试设计测试用例的方法。的方法。白盒测试的主要方法l逻辑驱动测试l基本路径测试 主要用于软件验证。使用程序设计的控制结构导出测试用例。一个显而易见的问题:一个完整的语句,未必是一行语句
6、 y=abs(x);if(x=0)y=sqrt(x);if(x=0)y=x;else y=abs(x);if(x=0)&(z=0)y=x*z;简单的赋值语句单分支语句双分支语句判断条件较复杂的单分支语句一些更复杂的语句 if(x100)printf(ERROR!);elseif(x=60)printf(OK!);elseprintf(FAIL!);for(i=0;i=0)y=sqrt(x);if(x=0)y=x;else y=abs(x);令x任取一值即可使本语句被执行令x任取一非负数值即可保证判断条件成立,语句被执行令x任取一值因为此二分支覆盖了全部的取值范围,x无论取什么值,都能使其中的一
7、个分支被执行 if(x=0)|(z=0)y=x*z;不管z,令x任取一非负数值不管x,令z任取一非负数值令x、z同时任取一非负数值这三种取值均能使判断条件成立令判断条件成立,语句即被执行 if(x100)printf(ERROR!);elseif(x=60)printf(OK!);elseprintf(FAIL!);令判断条件A成立,分支之一被执行令判断条件A不成立,但B成立,那么分支之二被执行令判断条件AB均不成立,则分支之三被执行A AB B以上三种取值,均能使这个分支语句得以执行 for(i=0;i3)/语句14 k=x3-1;5 j=sqrt(k);/语句26 printf(%d,%5
8、.2dn,k,j);7 如下的C函数:Q1:本函数中起作用的变量有哪几个?xQ2:用最简单的输入,使函数中的都得到执行:令x为4单分支语句 void DoWork(int x,int y,int z)1 2 int k=0,j=0;3 if(x3)&(z3)/语句14 k=x-1;5 else 6 k=sqrt(x);如下的C函数:Q1:本函数中起作用的变量有哪几个?Q2:用最简单的输入,使函数中的都得到执行x为4Q3:使函数中的每个语句都得到最充分的执行用例1:x为4用例2:x为3双分支语句1.语句覆盖:设计若干个测试用例,运行被测试程序,使得;此方法是把程序中的所有的语句都覆盖到;2.判定
9、覆盖(也称为分支覆盖):设计若干个测试用例,运行所测程序,使程序中每个判断的取真分支和取假分支各至少执行一次;(x3)&(z3)|(z3)|(z3)和(z3)为真和假各取一次;(z3)|(z3)|(z3)|(z3)和(z3)为真和假各取一次;(z3)|(z3)和(z3)|(z3)|(z3)和(z3)&(z5)j=x*y+10;/语句块2 j=j%3;/语句块3Yes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)函数的流程图语句覆盖为了说明简略,分别对各个判断的取真、取假分支编号为b、c、d、e。为了测试语句覆盖率只要设计一个测试用例就可以把三个执行语句块
10、中的语句覆盖了。测试用例输入为:x=4、y=5、z=5程序执行的路径是:abdYes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)该测试用例虽然覆盖了每条可执行语句,但并不能检查判断逻辑是否有问题,例如在第一个判断中把&错误的写成了|,则上面的测试用例仍可以覆盖所有的执行语句(即查不出写错了这个事实)可以说语句覆盖率是最弱的逻辑覆盖准则使程序中每个语句至少执行一次判定覆盖 对于上面的程序,如果设计两个测试用例则可以满足分支覆盖的要求。测试用例的输入为:x=4、y=5、z=5 abd x=2、y=5、z=5 ace 上面的两个测试用例虽然能够满足分支覆盖的
11、要求,但是也不能实现对判断条件的检查效果,如果把第二个条件y5错误地写成y3)&(z5)使程序中每个判断的取真分支和取假分支至少执行一次条件覆盖就是设计若干个测试用例,运行被测试对象,使得程序中每个判断的每个条件的所有可能取值至少执行一次。对例子中的所有条件取值加以标记。例如:对于第一个判断:条件1:x3 取真值为T1,取假值为-T1条件2:z5 取真值为T4,取假值为-T4Yes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)使程序中每个判断每个条件分别取真和取假各一次可以设计测试用例如下:测试用例 通过路径 条件取值覆盖分支x=4、y=6、z=5 ab
12、dT1、T2、T3、T4 bdx=2、y=5、z=5 ace-T1、-T2、-T3、-T4 ceYes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)如果设计了下面的测试用例,则虽然满足了条件覆盖,但只覆盖了第一个条件的取假分支和第二个条件的取真分支,又不满足分支覆盖的要求(be线路未执行)测试用例 通过路径 条件取值覆盖分支x=2、y=6、z=5 acd-T1、T2、-T3、T4 cdx=4、y=5、z=5 acdT1、-T2、T3、-T4 cd使程序中每个判断的取真分支和取假分支至少执行一次判定-条件覆盖 判定-条件覆盖就是设计足够的测试用例,使得判断
13、中每个条件的所有可能取值至少执行一次,同时每个判断的所有可能判断结果至少执行。根据定义只需设计以下两个测试用例便可以覆盖8个条件值以及4个判断分支。测试用例 通过路径 条件取值覆盖分支x=4、y=6、z=5 abdT1、T2、T3、T4 bdx=2、y=5、z=11ace-T1、-T2、-T3、-T4 ceYes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)判定-条件覆盖从表面来看,测试了所有条件的取值,但实际上,某些条件掩盖了另一些条件,即仍然有遗漏。例如:对于条件表达式(x3)&(z3)为假,则一般的编译器将不再判断是否(z5)来说,若x=4测试结果
14、为真,就认为表达式的结果为真,这时不再检查(y5)是否为真。可见,采用判定-条件覆盖,逻辑表达式中的错误不一定都能查出来。Yes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)条件组合覆盖:条件组合覆盖就是设计足够的测试用例,运行被测试对象,使得每一个判断的所有可能的条件取值至少执行一次。现在对例子中的各个判断的条件取值组合加以标记如下:1.x3,z3,z=10 记做T1-T2,第一个判断的取假分支3.x=3,z10 记做-T1 T2,第一个判断的取假分支4.x=10 记做-T1-T2,第一个判断的取假分支5.x=4,y5 记做T3 T4,第二个判断的取真
15、分支6.x=4,y5 记做-T3 T4,第二个判断的取真分支8.x!=4,y3)&(z5)测试用例 通过路径 条件取值覆盖组合号x=4、y=6、z=5abdT1、T2、T3、T4 1和5 x=4、y=5、z=15 acdT1、-T2、T3、-T4 2和6 x=2、y=6、z=5 acd-T1、T2、-T3、T4 3和7 x=2、y=5、z=15ace-T1、-T2、-T3、-T4 4和8Yes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)路径覆盖路径覆盖就是设计足够多的测试用例,覆盖被测试对象中的所有可能路径在上面的测试用例中再添加一个测试用例,则可对程
16、序进行全部的路径覆盖 测试用例 通过路径 覆盖条件 x=4、y=6、z=5 abdT1、T2、T3、T4x=4、y=5、z=15 acdT1、-T2、T3、-T4 x=2、y=6、z=15 ace-T1、-T2、-T3、-T4 x=5、y=6、z=5 abeT1、T2、-T3、T4 分析:分析:说明:说明:对这个对这个C C函数分别作六种覆盖函数分别作六种覆盖Main()int a,b;float c;if(a0)&(b0)c=c/a;/语句块1 if(a1)|(c1)c=c+1;/语句块2 c=b+c;/语句块36种覆盖标准的对比语句覆盖 每条语句至少执行一次 判定覆盖 每个判定的每个分支至
17、少执行一次 条件覆盖 每个判定的每个条件应取到各种可能的值 判定/条件覆盖 同时满足判定覆盖和条件覆盖 条件组合覆盖 每个判定中各条件的每一种组合至少出现一次 弱 发 现 错 误 能 力 强 路径覆盖 使程序中每一条可能的路径至少执行一次 语句覆盖发现错误能力最弱。判定覆盖包含了语句覆盖,但它可能会使一些条件得不到测试。条件覆盖对每一条件进行单独检查,一般情况下它的检错能力较判定覆盖强,但有时达不到判定覆盖的要求。判定/条件覆盖包含了判定覆盖和条件覆盖的要求,但由于计算机系统软件实现方式的限制,实际上不一定达到条件覆盖的标准。条件组合覆盖发现错误能力较强,凡满足其标准的测试用例,也必然满足前4
18、种覆盖标准。前5种覆盖标准把注意力集中在单个判定或判定的各个条件上,可能会使程序某些路径没有执行到。路径测试根据各判定表达式取值的组合,使程序沿着不同的路径执行,查错能力强。但由于它是从各判定的整体组合出发设计测试用例的,可能使测试用例达不到条件组合覆盖的要求。在实际的逻辑覆盖测试中,一般以条件组合覆盖为主设计测试用例,然后再补充部分用例,以达到路径覆盖测试标准。练习题:为以下流程图所示的程序段设计一组测试用例,要求分别满足语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组合覆盖和路径覆盖。一个被测试程序的流程图 作业题作业题试做出左边三角形问题的语句覆盖,条件覆盖,判定覆盖,判定条件覆盖、组合
19、条件覆盖的测试用例.并注明满足覆盖的条件.eg:a b c3 4 5 T1T2T3F4F5F6在不能做到所有路径覆盖的前提下,如在不能做到所有路径覆盖的前提下,如果某一程序的每一个独立路径都被测试果某一程序的每一个独立路径都被测试过,那么可以认为程序中的每个语句都过,那么可以认为程序中的每个语句都已经检验过了,即达到了语句覆盖。这已经检验过了,即达到了语句覆盖。这种测试方法就是通常所说的种测试方法就是通常所说的基本路径测基本路径测试方法试方法。Yes入口Noabc执行语句块2执行语句块1YesdNoe出口执行语句块3(x3)&(z5)函数的流程图基本路径测试 这个例子是一个很简单的程序函数,只
20、有四条路径。但在实践中,一个不太复杂的程序,其路径都是一个庞大的数字,要在测试中覆盖所有的路径是不现实的。为了解决这一难题,只得把覆盖的路径数压缩到一定限度内,例如,程序中的循环体只执行一次。基本路径测试就是这样一种测试方法,它在程序控制图的基础上,通过分析控制构造的环行复杂性,导出基本可执行路径集合,从而设计测试用例的方法。设计出的测试用例要保证在测试中程序的每一个可执行语句至少执行一次。在介绍基本路径方法之前,必须先介绍一种简单的控制流表示方法,即流图。控制流图(可简称流图)是对程序流程图进行简化后得到的,它可以更加突出的表示程序控制流的结构。控制流图中包括两种图形符号:节点和控制流线。节
21、点由带标号的圆圈表示,可代表一个或多个语句、一个处理框序列和一个条件判定框(假设不包含复合条件)。控制流线由带箭头的弧或线表示,可称为边。它代表程序中的控制流。对于复合条件,则可将其分解为多个单个条件,并映射成控制流图。常见结构的控制流图常见结构的控制流图常见结构的控制流图其中,包含条件的节点被称为判定节点判定节点(也叫谓词节点),由判定节点发出的边必须终止于某一个节点,由边和节点所限定的范围被称为区域区域。顺序结构IF选择结构WHILE重复结构UNTIL重复结构CASE多分支结构if(a|b)执行x;else 执行y;复合条件下的控制流图复合条件下的控制流图 (a)(a)程序;程序;(b)(
22、b)控制流图控制流图 基本路径测试方法是在控制流图的基础上基本路径测试方法是在控制流图的基础上,通过分析控制结构的环形复杂度,导出,通过分析控制结构的环形复杂度,导出执行路径的基本集合,再从该基本集设计执行路径的基本集合,再从该基本集设计测试用例。基本路径测试方法包括测试用例。基本路径测试方法包括4 4个步骤个步骤:(1 1)画出程序的画出程序的控制流图控制流图。(2 2)计算程序的计算程序的环形复杂度环形复杂度,导出程序基本,导出程序基本路径集中的路径集中的独立路径独立路径条数,这是确定程序条数,这是确定程序中每个可执行语句至少执行一次所必须的中每个可执行语句至少执行一次所必须的测试用例数目
23、的上界。测试用例数目的上界。(3 3)导出基本路径集,确定程序的独立路径导出基本路径集,确定程序的独立路径。(4 4)根据根据(3)(3)中的独立路径,设计测试用例中的独立路径,设计测试用例的输入数据和预期输出。的输入数据和预期输出。第一步:画出控制流图c/c+语句中的控制语句表示含义如下:图中的每一个圆称为流图的结点,代表一条或多条语句。流图中的箭头称为边或连接,代表控制流。为了说明流图的用法,我们采用过程设计表示法,此处,流程图用来描述程序控制结构。可将流程图映射到一个相应的流图(假设流程图的菱形决定框中不包含复合条件)。在流图中,每一个圆,称为流图的结点,代表一个或多个语句。一个处理方框
24、序列和一个菱形决测框可被映射为一个结点,流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个结点,即使该结点并不代表任何语句(例如:参见if-else-then结构的符号)。由边和结点限定的范围称为区域。计算区域时应包括图外部的范围。任何过程设计都要被翻译成控制流图。void Sort(int iRecordNum,int iType)1 2 int x=0;3 int y=0;4 while(iRecordNum-0)5 6if(iType=0)7 x=y+2;8 else9 if(iType=1)10 x=y+10;11 else12 x=y+20;13 14
25、 如下面的C函数:在将程序流程图简化成控制流图时,应注意:在选择或多分支结构中,分支的汇聚处应有一个。边和结点圈定的区域叫做当对区域计数时,图形外的区域也应记为一个区域。如何根据程序流程图画出控制流程图?void Sort(int iRecordNum,int iType)1 2 int x=0;3 int y=0;4 while(iRecordNum-0)5 6if(iType=0)7 x=y+2;8 else9 if(iType=1)10 x=y+10;11 else12 x=y+20;13 14 画出其程序流程图如下:void Sort(int iRecordNum,int iType)
26、1 2 int x=0;3 int y=0;4 while(iRecordNum-0)5 6if(iType=0)7 x=y+2;8 else9 if(iType=1)10 x=y+10;11 else12 x=y+20;13 14 第二步:计算环形复杂度 环形复杂度是一种为程序逻辑复杂性提供定量测度的软件度量,将该度量用于计算程序的基本的独立路径数目,为确保所有语句至少执行一次的测试数量的上界。独立路径必须包含一条在定义之前不曾用到的边。有以下三种方法计算环形复杂度:1.流图中区域的数量对应于环型的复杂性;2.给定流图G的环形复杂度:V(G),定义为V(G)=E-N+2,E是流图中边的数量,
27、N是流图中结点的数量;3.给定流图G的环形复杂度:V(G),定义为V(G)=P+1,P是流图G中判定结点的数量。程序流程图和对应的控制流图如下:对应上面图中的环形复杂度,计算如下:流图中有四个区域;V(G)=10条边-8结点+2=4;V(G)=3个判定结点+1=4。第三步:导出测试用例 根据上面的计算方法,可得出四个独立的路径:路径1:4-14 路径2:4-6-7-13-4-14 路径3:4-6-8-10-13-4-14 路径4:4-6-8-11-13-4-14根据上面的独立路径,去设计输入数据,使程序分别执行到上面四条路径,即完成了测试用例的设计第四步:准备测试用例为确保基本路径集中的每一条路径的执行,根据判断结点给出的条件,选择适当的数据以保证某一条路径可以被测试到,满足上面例子基本路径集的测试用例是:路径1:4-14输入数据:iRecordNum0,或者取iRecordNum1)&(B=0)1 if(A1)&(B=0)2 X=X/A;2 X=X/A;3 if(A=2)|(X1)3 if(A=2)|(X1)4 X=X+1;4 X=X+1;5 5 复合判定的例子改为单个条件判定的嵌套结构的例子