本章节主要讲解“软件测试的基本路径覆盖”的内容,基本路径覆盖法是指在程序控制流图的基础上,通过分析控制结构的环路复杂性,导出基本可执行路径集合,设计测试用例的方法。该方法把覆盖的路径数压缩到一定限度内,程序中的循环体最多只执行一次。设计出的测试用例要保证在测试中,程序的每一个可执行语句至少执行一次。
基本路径覆盖分析法步骤如下:
(1)从详细设计导出控制流图。
符号“○”为控制流图的一个结点,表示一个或多个无分支的源程序语句。箭头为边,表示控制流的方向。
常见的顺序结构、If 选择结构、While 重复选择结构、Until 重复选择结构和Case 多分支选择结构控制流图画法如图10-10 所示。
图10-10 常见结构控制流图
在选择或多分支结构中,分支的汇聚处应有一个汇聚结点。边和结点圈定的区域叫做区域,当对区域计数时,图形外的区域也应记为一个区域。如果判断中的条件表达式是由一个或多个逻辑运算符(OR、AND、NAND、NOR)连接的复合条件表达式,则需要改为一系列只有单条件的嵌套的判断。如图10-11 所示为程序流程图与控制流图的关系。
图10-11 程序流程图与控制流图的关系
(2)确定控制流图的环形复杂度。
环形复杂度也称为圈复杂度,它是一种为程序逻辑复杂度提供定量尺度的软件度量。程序的环形复杂度是指程序基本路径集中的独立路径数量,这是确保程序中每个可执行语句至少执行一次所必需的测试用例数目的上限。独立路径是指程序中至少引入了一个新的处理语句集合或一个新条件的程序通路。从控制流图的角度来说,独立路径是指必须至少包含一条在本次定义路径之前不曾用过的边。
环形复杂度以图论为基础,为我们提供了非常有用的软件度量。
可用如下三种方法来计算环形复杂度:
第一种方法:计算控制流图中的区域数量,控制流图中的区域等于环形复杂度。
第二种方法:给定控制流图G 的环形复杂度V(G),定义V(G) = E-N+2(其中E是控制流图中边的数量,N 是控制流图中的结点数量)。
第三种方法:给定控制流图G 的环形复杂度V(G),也可定义为 V(G) = P+1(其中P 是控制流图G 中的结点,但该结点至少需要输出2 条或2 条以上的边)。
(3)确定独立路径的基本集。
(4)导出测试用例,确保基本路径集中的每一条路径都被执行。
【实例】使用基本路径覆盖法对下面一段程序进行分析,并导出测试用例。
被测试代码如下:
//Function: BOOL IsCodeLine (CString szStatFileLine, BOOL &bIsComment)
//Description: 判断当前字符串是否是代码行
//Calls: 无
//Input: szStatFileLine——文件中当前行的字符串,该行字符串不是空行
// bIsComment——标识当前行是否处于注释体内
// True——处于注释体内,False——不处于注释体内
//Output: bIsComment:如果该行为注释的最后一行,bIsComment 赋值False
//Return: RET_OK——代码行,RET-FAIL——注释行
//Others: 无
BOOL CCounter::IsCodeLine(CString szStatFileLine,BOOL &bIsComment)
{
//定义代码行标志
1 int iCodeFlag=RET_FAIL;
//记录当前字符串的长度
2 int iCodeLineLen=0;
//循环变量
3 int iLoop=0;
//从字符串中获取的两个字符,判断是否为"/*"或者"*/"
4 CString szTmpCommLine;
//从字符串中获取的一个字符,判断是否为代码字符
5 CString szTmpCodeLine;
//删除szStatFileLine 的首尾空格,Tab,回车,换行
6 szStatFileLine.TrimLeft();
7 szStatFileLine.TrimRight();
//iCodeLineLen = szStatFileLine 的字符串长度
8 iCodeLineLen = szStatFileLine.GetLength();
//如果没有读取到字符串的倒数第二个字符,循环继续
9 while (iLoop < iCodeLineLen - 1)
{
//szTmpCommLine 等于szStatFileLine 的第iLoop 和第(iLoop+1)个字符
szTmpCommLine = (CString)szStatFileLine.GetAt(iLoop) +
(CString)szStatFileLine.GetAt(iLoop+1);
//szTmpCodeLine 等于szStatFileLine 的第iLoop 个字符
11 szTmpCodeLine = szStatFileLine.GetAt(iLoop);
//如果原来代码未处于注释段中,发现字符串"/*"则注释段开始
12 if( (szTmpCommLine == "/*") && (bIsComment == False) )
{
//注释标志位被置为True
13 bIsComment = True;
//循环变量加2,越过"/*",读取注释体内的字符
14 iLoop+=2;
15 continue;
}
//如果原来代码处于注释段中,发现字符串"*/"则注释段结束
16 else if ( (szTmpCommLine == "*/") && ( bIsComment == True) )
{
//注释标志位被置为False
17 bIsComment = False;
//循环变量加2,越过"*/",读取注释体外的字符
18 iLoop+=2;
19 continue;
}
//如果当前的字符非tab 字符、非空格字符,并且没有处于注释体内,那么判断该行是
//代码行
20 else if ( (szTmpCodeLine != " ") && (szTmpCodeLine != " ")
&& (bIsComment == False))
{
21 iCodeFlag = RET_OK;
}
//循环变量加1,读取字符串中的下一个字符
22 iLoop++;
}//
return iCodeFlag;
}
第一步:分析被测试程序,画出程序流程图和控制流图,如图10-12 所示。
图10-12 程序流程图与控制流图
第二步:确定控制流图的复杂度,该实例的复杂度为9(复杂度=21-14+2)。
第三步:确定独立路径的基本集,该实例独立路径的基本集如下:
路径1:开始→(1-8,9)→结束;
路径2:开始→(1-8,9)→(10-11,12a)→(16a)→(20a)→(22)→(1-8,9)→结束;
路径3:开始→(1-8,9)→(10-11,12a)→(16a)→(20a)→(20b)→(22)→(1-8,9)→结束;
路径4:开始→(1-8,9)→(10-11,12a)→(16a)→(20a)→(20b)→(20c)→(22)→(1-8,9)→结束;
路径5:开始→(1-8,9)→(10-11,12a)→(16a)→(20a)→(20b)→(20c)→(21)→(22)→(1-8,9)→结束;
路径6:开始→(1-8,9)→(10-11,12a)→(12b)→(13-15)→(1-8,9)→结束;
路径7:开始→(1-8,9)→(10-11,12a)→(16a)→(16b)→(17-19)→(1-8,9)→结束;
路径8:开始→(1-8,9)→(10-11,12a)→(12b)→(16a)→(20a)→(22)→(1-8,9)→结束;
路径9:开始→(1-8,9)→(10-11,12a)→(16a)→(16b)→(20a)→(22)→(1-8,9)→结束。
第四步:依据独立路径的基本集导出测试用例。该实例中包括9 个测试用例,此处不一一列出,以路径1 为例进行导出测试用例操作,导出的测试用例见表10-9。
表10-9 路径1 导出的测试用例
本章节关于“软件测试的基本路径覆盖”的内容就学习到这里,大家觉得文章有用的话记得每天来这里和小编一起学习涨薪技能哦。