定义
基本路径测试法又称独立路径测试,是在程序控制流图的基础上,通过分析控制结构的环路复杂性,导出基本可执行路径集合,从而设计出相应的测试用例的方法。设计出的测试用例要保证在测试中程序的语句覆盖100%,条件覆盖100%。
测试步骤
基本路径测试法包括以下4个步骤:
(1) 画出程序的控制流图:描述程序控制流的一种图示方法;
(2) 计算程序的环形复杂性:McCabe复杂性度量;从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界;
(3) 导出测试用例;根据圈复杂度和程序结构设计用例数据输入和预期结果;
(4) 准备测试用例,确保基本路径集中的每一条路径的执行;
第一步:画出控制流图
流程图用来描述程序控制结构。可将流程图映射到一个相应的流图(假设流程图的菱形决定框中不包含复合条件)。在流图中,每一个圆,称为流图的结点,表示一个或多个无分支的语句或源程序语句。一个处理方框序列和一个菱形决测框可被映射为一个结点,流图中的箭头,称为边或连接,代表控制流,类似于流程图中的箭头。一条边必须终止于一个结点,即使该结点并不代表任何语句。由边和结点限定的范围称为区域,计算区域时应包括图外部的范围。
在控制流图中的两种图形符号:
-
结点:
①标有编号的圆圈;
②程序流程图中矩形框所表示的处理 ;
③菱形表示的两个甚至多个出口判断;
④多条流线相交的汇合点。
-
边或连接:
①箭头;
②与程序流程图中的流线一致,表明了控制的顺序;
③控制流线通常标有名字。
常见结构的控制流图
在将程序流程图简化成控制流图时,应注意:
-
在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。
-
如果判断中的条件表达式是由一个或多个逻辑运算符 (OR, AND, NAND, NOR) 连接的复合条件表达式,则需要改为一系列只有单条件的嵌套的判断。
-
在程序流图中一系列的顺序执行语句可以合成为一个结点,但是对于多分支的判断则需要分界为独立的分支,每个分支一个结点。
🌰举个栗子:
根据下面的java程序画出流程图和对应的控制流图
public class Test{
public void Sort(int iRecordNum,int iType){
int x = 0;
int y = 0;
while(iRecordNum-->0){
if(iType==0){
x = y + 2;
break;
}else{
if(iType==1){
x = y + 10;
}else{
x = y + 20;
}
}
}
}
}
程序流程图和对应的控制流图如下:
第二步:计算圈复杂度
圈复杂度用来衡量一个模块判定结构的复杂程度,将该度量用于计算程序的基本的独立路径数目,为确保所有语句至少执行一次的测试数量的上界。一条独立路径是指,和其他的独立路径相比,至少引入一个新处理语句或一个新判断的程序通路,通俗的来说就是该路径要比其他路径至少多一个新的路径,并且该路径应该是从头至尾的,不可间断。
有以下几种方法计算圈复杂度:
-
给定流图G的圈复杂度V(G),定义为V(G)=Area,Area是流程图中的区域数量(即为封闭区域数量+1);
-
给定流图G的圈复杂度V(G),定义为V(G)=E-N+2,E是流图中边的数量,N是流 图中结点的数量;
-
给定流图G的圈复杂度V(G),定义为V(G)=P+1,P是流图G中判定结点的数量。
根据圈复杂度计算,上面例3的复杂度计算如下:
-
V(G)=Area,V(G)=4。
-
V(G)=E-N+2,V(G)=10-8+2=4。
-
V(G)=P+1,V(G)=3+1=4。[判定结点:4、6、9]
第三步:导出测试用例
根据上面的计算方法,可得出四个独立的路径,V(G)值正好等于该程序的独立路径的条数。
路径1:4-14
路径2:4-6-7-14
路径3:4-6-9-10-13-4-14
路径4:4-6-9-12-13-4-14
根据上面的独立路径,去设计输入数据,使程序分别执行到上面四条路径。
第四步:准备测试用例
为了确保基本路径集中的每一条路径的执行,根据判断结点给出的条件,选择适当的数据以保证某一条路径可以被测试到,满足上面例子基本路径集的测试用例是:
路径1:4-14:
① 结点4代码while(iRecordNum-->0),取值False;
② 输入数据:iRecordNum≤0的任何一个值。
路径2:4-6-7-14:
① 结点4代码while(iRecordNum-->0),取值True;
② 结点6代码iType= =0,取值True;
③ 输入数据:iRecordNum=1,iType=0。
路径3:4-6-9-10-13-4-14:
① 结点4代码while(iRecordNum-->0),取值True;
② 结点6代码iType= =0,取值False;
③ 结点9代码iType= =1,取值True;
④ 结点10代码x=y+10;
⑤ 输入数据:iRecordNum=1,iType=1。
路径4:4-6-9-12-13-4-14
① 结点4代码while(iRecordNum-->0),取值True;
② 结点6代码iType= =0,取值False;
③ 结点9代码iType= =1,取值False;
④ 结点12代码x=y+20;
⑤ 输入数据:iRecordNum=1,iType=2。
测试用例 | 输入数据 |
---|---|
Case1 | iRecordNum=0 iType=0 |
Case2 | iRecordNum=1 iType=0 |
Case3 | iRecordNum=1 iType=1 |
Case4 | iRecordNum=1 iType=2 |
案例分析
案例一
分析下面的代码段,设计一组满足基本路径覆盖的测试用例。
案例步骤
-
分析代码,画出程序流程图;
-
根据程序流程图画出控制流图;
-
计算圈复杂度;
-
导出测试用例;
-
准备测试用例。
代码段
public void function(int x, int y, int z)
{
if ((y > 1) && (z == 0))
{
x = x/y;
}
if ((y == 2) || (x > 1))
{
x = x+1;
}
y = x + z;
}
流程图
步骤1:导出过程的控制流图:根据流程图分析结点:
(1)结点1:开始;
(2)(y>1)&&(z==0)
为逻辑运算符 AND
连接的复合条件表达式,需要改为单条件的判定,分解为2个结点,结点2:z==0
;结点3:y>1
;
(3)结点4:x=x/y
;
(4)(y==2)||(x>1)
为逻辑运算符 OR
连接的复合条件表达式,需要改为单条件的判定,分解为2个结点,结点5:y==2
;结点6:x>1
;
(5)结点7:x=x+1
;
(6)结点8:y=y+z
(7)结点9:结束。
步骤2:确定环形复杂性度量V(G):
(1)V(G)= 5 (个区域)[区域1:2-3-5;区域2:3-4-5;区域3:5-6-7;区域4:6-7-8;区域5:外部];
(2)V(G)=E–N+2=12–9+2=5;其中E为流图中的边数,N为结点数;
(3)V(G)=P+1=4+1=5;其中P为判定结点的个数。在流图中,结点2、3、5、6是判定结点。
步骤3:确定基本路径集合(即独立路径集合)。于是可确定5条独立的路径:
路径1:1-2-5-6-8-9
路径2:1-2-5-7-8-9
路径3:1-2-5-6-7-8-9
路径4:1-2-3-5-6-8-9
路径5:1-2-3-4-5-6-8-9
步骤4:为每一条独立路径各设计一组测试用例,以便强迫程序沿着该路径至少执行一次。
(1)路径1(1-2-5-6-8-9)的测试条件:
z≠0,y≠2,x<=1;
(2)路径2(1-2-5-7-8-9)的测试条件:
z≠0,y=2;
(3)路径3(1-2-5-6-7-8-9)的测试条件:
z≠0,y≠2,x>1;
(4)路径4(1-2-3-5-6-8-9)的测试条件:
z=0,y<=1,x<=1;
(5)路径5(1-2-3-4-5-6-8-9)的测试条件:
z=0,y>1&&y≠2,x<=1;
用例设计
基本路径覆盖法用例如下:
测试用例 | 输入 | 独立路径 |
---|---|---|
CASE1 | x=1, y=1,z=1 | 1-2-5-6-8-9 |
CASE2 | x=2,y=2,z=1 | 1-2-5-7-8-9 |
CASE3 | x=2,y=1,z=1 | 1-2-5-6-7-8-9 |
CASE4 | x=1, y=1,z=0 | 1-2-3-5-6-8-9 |
CASE5 | x=1, y=3,z=0 | 1-2-3-4-5-6-8-9 |
案例二
分析下面的代码段,设计一组满足基本路径覆盖的测试用例。
案例步骤
-
分析代码,画出程序流程图;
-
根据程序流程图画出控制流图;
-
计算圈复杂度;
-
导出测试用例;
-
准备测试用例。
代码段
public void TestS(int[] scorces) {
int Average = 0;
int sum = 0;
int n1 = 0;
int n2 = 0;
int i = 0;
while(scorces[i]!=-1 && n2<4) {
n2 = n2 + 1;
if(scorces[i] >= 0 && scorces[i] <= 100) {
n1 = n1 + 1;
sum = sum +scorces[i];
}
i = i + 1;
}
if(n1 > 0){
Average = sum/n1;
}else{
Average = -1;
}
}
流程图
步骤1:导出过程的控制流图:根据流程图分析结点:
(1)结点1:开始
(2)结点2:Average=0
,sum=0
,n1=0
,n2=0
,i=0
;
(3)Score[i]!=-1 and n2<4
为逻辑运算符 FAND
连接的复合条件表达式,需要改为单条件的判定,分解为2个结点,结点3:Score[i]!=-1
;结点4:n2<4
;
(4)结点5:n2=n2+1
;
(5)Score[i]>=0 and Score[i]<=100
逻辑运算符 AND
连接的复合条件表达式,需要改为单条件的判定,分解为2个结点,结点6:Score[i]>=0
;结点7:Score[i]<=100
;
(6)结点8:n1=n1+1
,sum=sum+Score[i]
(7)结点9:i=i+1
(8)结点10:n1>0
(9)结点11:Average=-1
(10)结点12:Average=sum/n1
(11)结点13:结束
步骤2:确定环形复杂性度量V(G):
(1)V(G)= 6 (个区域)[区域1:3-4-10;区域2:10-11-12-13;区域3:6-7-9;区域4:7-8-9;区域5:3-4-5-6-9;区域6:外部];
(2)V(G)=E–N+2=17–13+2=6;其中E为流图中的边数,N为结点数;
(3)V(G)=P+1=5+1=6;其中P为判定结点的个数。在流图中,结点3、4、6、7、10是判定结点。
步骤3:确定基本路径集合(即独立路径集合)。于是可确定6条独立的路径:
路径1:1-2-3-10-11-13
路径2:1-2-3-10-12-13
路径3:1-2-3-4-10-12-13
路径4:1-2-3-4-5-6-9-3…
路径5:1-2-3-4-5-6-7-9-3…
路径6:1-2-3-4-5-6-7-8-9-3…
步骤4:为每一条独立路径各设计一组测试用例,以便强迫程序沿着该路径至少执行一次。
(1)路径1(1-2-3-10-11-13)的测试条件:
Score[ i ]= – 1 ;
(2)路径2(1-2-3-10-12-13)的测试条件:
Score[ i ]= – 1,n1>0 ;
(3)路径3(1-2-3-4-10-12-13)的测试条件:
Score[ i ]!= – 1,n2≥4;
n2≥4
,输入多于4个有效分数,即试图处理5个分数,要求前5个为有效分数;
(4)路径4(1-2-3-4-5-6-9-3…)的测试条件:
Score[i]!= – 1,n2<4,Score[i]< 0;
(5)路径5(1-2-3-4-5-6-7-9-3…)的测试条件:
Score[i]!= – 1,n2<4,Score[i]>100;
(6)路径6(1-2-3-4-5-6-7-8-9-3…)的测试条件:
Score[i]=有效分数,n2<4;
用例设计
基本路径覆盖法用例如下:
测试用例 | 输入 | 独立路径 |
---|---|---|
CASE1 | -1 | 1-2-3-10-11-13 |
CASE2 | 80 | 1-2-3-4-5-6-7-8-9-3… |
102 | 1-2-3-4-5-6-7-9-3… | |
-2 | 1-2-3-4-5-6-9-3… | |
40 | 1-2-3-4-5-6-7-8-9-3… | |
60 | 1-2-3-4-10-12-13 | |
CASE3 | 0 | 1-2-3-4-5-6-7-8-9-3… |
-1 | 1-2-3-10-12-13 |