实验3逻辑覆盖测试用例设计1. 实验目标 能够依据程序画出程序流程图。  理解常用覆盖方法的内涵。  理解常用覆盖方法的强弱关系。  能够使用常用覆盖方法设计测试用例。 2. 背景知识 白盒测试通常采用静态测试方法和动态测试方法开展。动态测试是参照系统需求或测试规则,通过预先设计一组测试输入,并借助此输入动态运行程序,从而达到发现程序错误的过程。 覆盖测试是动态测试中的一类有效测试方法,主要包括逻辑覆盖、基本路径测试等。其中,逻辑覆盖基于程序内部的逻辑结构,通过对程序逻辑结构的遍历实现程序的覆盖。依据覆盖源程序结构的详尽程度,可分为语句覆盖、判定覆盖、条件覆盖、条件判定覆盖、条件组合覆盖和路径覆盖6种类型,具体介绍如下。 1) 语句覆盖 (1) 语句覆盖是一类比较弱的测试标准,具体是指选择足够的测试用例,使程序中的每个语句至少都能被执行一次。 (2) 局限性: 测试不充分,对程序执行逻辑的覆盖率较低,属于最弱的覆盖方式。 2) 判定覆盖 (1) 判定覆盖又称分支覆盖,是比语句覆盖稍强的一类测试标准,具体是指选择足够的测试用例,使程序中的各个判定获得每一种可能的结果至少一次,也就是说,使各个判定的每个分支至少都被执行一次。 (2) 局限性: 测试不充分,仅对整个判定的最终取值进行各方面的度量,但判定内部每一个子表达式的取值未被考虑。 3) 条件覆盖 (1) 条件覆盖是比判定覆盖更强的一类测试标准,具体是指选择足够的测试用例,使程序各判定中的每个条件获得各种可能的取值。 (2) 局限性: 测试不充分,虽弥补了判定覆盖的漏洞,对判定内部每一个子表达式的取值进行了度量,但条件覆盖并不能满足判定覆盖。 4) 条件判定覆盖 (1) 条件判定覆盖综合了判定覆盖和条件覆盖特点,是比条件覆盖更强的一类测试标准,具体是指选择足够的测试用例,使程序中各判定的每个分支至少都被执行一次,且使各判定中的每个条件获得各种可能的取值。 (2) 局限性: 测试不充分,未考虑单个判定对整体程序的影响,对程序执行逻辑的覆盖率较低。 5) 条件组合覆盖 (1) 条件组合覆盖是指选择足够的测试用例,使判定中条件的各种组合都至少被执行一次。 (2) 局限性: 测试不充分,某些情况下可遗漏覆盖部分路径,且组合数量相对较大,往往花费较多的时间。 6) 路径覆盖 (1) 路径覆盖是相当强的一类覆盖标准,具体是指设计足够多的测试用例,使程序中所有可能的路径被执行一次。 (2) 局限性: 测试不充分,测试所需用例数量相对较大,使工作量呈指数级增长。 值得提醒的是,软件评测师考试中,逻辑覆盖相关知识点往往占据一定的分值,题型多为采用6种覆盖方式进行测试用例的设计和依据各类覆盖的强弱关系进行语句判断。 因此,针对各类覆盖的强弱关系,总结如下。 (1) 满足条件组合覆盖的测试用例一定满足语句覆盖、判定覆盖、条件覆盖和条件判定覆盖。 (2) 满足条件判定覆盖的测试用例一定满足语句覆盖、条件覆盖和判定覆盖。 (3) 满足判定覆盖的测试用例一定满足语句覆盖。 (4) 满足条件覆盖的测试用例不一定满足语句覆盖及判定覆盖。 综上所述,各类覆盖均不是十全十美的,仅使用一种覆盖往往会导致测试片面、不充分,实际测试工作中通常会综合采用多种覆盖。例如,测试通过准则可能会要求语句覆盖达到100%、判定覆盖达到90%等。 下面通过两个任务从实践角度介绍6种逻辑覆盖方法的应用。 3. 实验任务任务1: 针对源程序1采用6种逻辑覆盖方法设计测试用例源程序1: #include void main() { float A,B,X; scanf("%f%f%f",&A,&B,&X); if((A>1)&&(B==0)) X=X/A; if((A==2)||(X>1)) X=X+1; printf("%f",X); } 测试用例设计: 第1步,绘制程序流程图,如图3.1所示。 图3.1程序流程图(任务1) 第2步,设计测试用例满足语句覆盖,如表3.1所示。表3.1语句覆盖测试用例(任务1) 用例编号测试用例覆盖路径1A=2,B=0,X=3a—c—e第3步,设计测试用例满足判定覆盖,如表3.2所示。其中,if((A>1)&&(B==0))、if((A==2)||(X>1))为源程序中的两个判定。在此,考虑两个判定的每个分支被执行一次即可。表3.2判定覆盖测试用例(任务1) 用例编号测试用例覆盖路径1A=3,B=0,X=1a—c—d2A=2,B=1,X=3a—b—e第4步,设计测试用例满足条件覆盖,如表3.3所示。其中,if((A>1)&&(B==0))、if((A==2)||(X>1))为源程序中的两个判定,而(A>1)、(B==0)、(A==2)和(X>1)为两个判定中的4个条件。在此,考虑(A>1)、(A<=1)、(B==0)、(B!=0)、(A==2)、(A!=2)、(X>1)和(X<=1)8种取值均被执行一次即可。表3.3条件覆盖测试用例(任务1) 用例编号测试用例覆盖条件1A=2,B=1,X=4(A>1)、(B!=0)、(A==2)、(X>1)2A=-1,B=0,X=1 (A<=1)、(B==0)、 (A!=2)、(X<=1)第5步,设计测试用例满足条件判定覆盖,如表3.4所示。在此,需同时满足条件覆盖和判定覆盖的要求。表3.4条件判定覆盖测试用例(任务1) 用例编号测试用例覆盖路径覆盖条件1A=2,B=0,X=4a—c—e(A>1)、(B==0)、(A==2)、(X>1)2A=1,B=1,X=1a—b—d(A<=1)、(B!=0)、(A!=2)、(X<=1)第6步,设计测试用例满足条件组合覆盖,如表3.5所示。其中,if((A>1)&&(B==0))、if((A==2)||(X>1))为源程序中的两个判定。在此,考虑((A>1)&&(B==0))、((A>1)&&(B!=0))、((A<=1)&&(B==0))、((A<=1)&&(B!=0))、((A==2)||(X>1))、((A==2)||(X<=1))、((A!=2)||(X>1))及((A!=2)||(X<=1))8种组合情况均被执行一次即可。表3.5条件组合覆盖测试用例(任务1) 用例编号测试用例覆盖条件组合1A=2,B=0,X=4((A>1)&&(B==0))、((A==2)||(X>1))2A=2,B=1,X=1((A>1)&&(B!=0))、((A==2)||(X<=1))3A=1,B=0,X=2((A<=1)&&(B==0))、((A!=2)||(X>1))4A=1,B=1,X=1((A<=1)&&(B!=0))、((A!=2)||(X<=1))注意: 条件组合仅仅针对同一个判定语句内存在多个条件的情况,此情况下,将这些条件的取值进行笛卡尔乘积组合即可。也就是说,对于不同的判定无须考虑条件组合,以及对于单条件的判断语句仅需要满足自身所有取值即可。 该注意同样适用于任务2,不再赘述。 第7步,设计测试用例满足路径覆盖,如表3.6所示。在此,需满足程序中所有可能的路径被执行一次的要求。表3.6路径覆盖测试用例(任务1) 用例编号测试用例覆盖路径1A=1,B=1,X=1a-b-d2A=1,B=1,X=2a-b-e3A=3,B=0,X=1a-c-d4A=2,B=0,X=4a-c-e注意: 实际设计出的覆盖路径及输入数据如果与上述设计不尽相同,则并非一定有误。例如在判定覆盖中,可选择a—c—e路径和 a—b—d路径的组合,也可选择a—c—d路径和a—b—e路径的组合,均满足判定覆盖的要求。因此,本任务的操作步骤及用例仅供参考。任务2: 针对源程序2采用6种逻辑覆盖方法设计测试用例 源程序2: int testing(int x, int y) { int software=0; if((x>0) && (y>0)) { software=x+y+10; } else { software=x+y-10; } if(software<0) { software=0; } return software; }第1步,绘制程序流程图,如图3.2所示。 图3.2程序流程图(任务2) 第2步,设计测试用例满足语句覆盖,如表3.7所示。表3.7语句覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=3,y=3a—b—e—f2x=-3,y=0a—c—d—f第3步,设计测试用例满足判定覆盖,如表3.8所示。其中,if((x>0)&&(y>0))、if(software<0)为源程序中的两个判定。在此,考虑两个判定的每个分支被执行一次即可。表3.8判定覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=3,y=3a—b—e—f2x=-3,y=0a—c—d—f第4步,设计测试用例满足条件覆盖,如表3.9所示。其中,if((x>0)&&(y>0))、if(software<0)为源程序中的两个判定,而x>0、y>0和software<0为两个判定中的3个条件。在此,考虑(x>0)、(x<=0)、(y>0)、(y<=0)、(software<0)和(software>=0)6种取值均被执行一次即可。表3.9条件覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=3,y=3a—b—e—f2x=-3,y=0a—c—d—f第5步,设计测试用例满足条件判定覆盖,如表3.10所示。在此,需同时满足条件覆盖和判定覆盖的要求。表3.10条件判定覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=3,y=3a—b—e—f2x=-3,y=0a—c—d—f第6步,设计测试用例满足条件组合覆盖,如表3.11所示。其中,if((x>0)&&(y>0))、if(software<0)为源程序中的两个判定。在此,考虑((x>0) && (y>0))、((x>0) && (y<=0))、((x<=0) && (y>0))、((x<=0) && (y<=0))4种情况,以及(software<0)和(software>=0)两种取值均被执行一次即可。表3.11条件组合覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=-3,y=0a—c—d—f2x=-3,y=2a—c—d—f续表 用例编号测试用例覆盖路径3x=-3,y=0a—c—d—f4x=3,y=3a—b—e—f第7步,设计测试用例满足路径覆盖,如表3.12所示。在此,需满足程序中所有可能的路径被执行一次的要求。表3.12路径覆盖测试用例(任务2) 用例编号测试用例覆盖路径1x=3,y=5a—b—e—f2x=0,y=12a—c—e—f3该路径不可能a—b—d—f4x=-8,y=3a—c—d—f同任务1中的介绍,也可设计不同于上述覆盖路径及输入数据的测试用例。上述操作步骤及用例仅供参考。 4. 拓展练习 (1) 依据源程序绘制程序流程图,并采用6种覆盖方式(语句覆盖、判定覆盖、条件覆盖、条件判定覆盖、条件组合覆盖及路径覆盖)进行白盒测试用例设计。 源程序: int Test(int i_count, int i_flag) { int i_temp=1; while(i_count>0) { if(0==i_flag) { i_temp=i_count+100; break; } else { if(1==i_flag) { i_temp=i_temp10; } else { i_temp=i_temp20; } } i_count--; } return i_temp; }(2) 依据源程序绘制程序流程图,并采用6种覆盖方式(语句覆盖、判定覆盖、条件覆盖、条件判定覆盖、条件组合覆盖及路径覆盖)进行白盒测试用例设计。 源程序: int _tmain(int argc, _TCHAR argv[]) { int x,y; scanf("%d%d",&x,&y); if(x>0 && y>0) { int i=1; if(x>y) { while((xi)% y !=0) i++; printf("%d\\n",xi); } else { while((yi)% x !=0) i++; printf("%d\\n",yi); } } return 0; }实验4基本路径测试用例设计1. 实验目标 理解控制流图,并掌握控制流程图的画法。  掌握程序环路复杂度的计算方法。  能够快速找出程序中的基本路径。  能够使用基本路径测试法设计测试用例。 2. 背景知识 覆盖测试是动态测试中的一类有效测试方法,除逻辑覆盖测试法之外,基本路径测试法在覆盖测试中也占有极其重要的地位。 基本路径测试法是在程序控制流图的基础上,通过计算程序环路复杂度,找出基本路径的集合,然后据此设计测试用例。其中,设计出的测试用例需确保源程序的每个可执行语句至少执行一次。 基本路径测试法的定义说明了该测试法的操作步骤。为加深对基本路径测试法的理解,下面依据基本路径测试法的操作步骤,依次介绍定义中涉及的知识点。 1) 依据源程序画出控制流图 图4.1顺序结构 什么是控制流图?控制流图是描述程序控制流的一种图示方法,通常由“○”及“→”两种图形符号构成。其中,“○”称为控制流图的结点,代表一条或多条语句;“→”称为边或连接,代表控制流的走向;“○”和“→”圈定的空间称为区域,当对区域计数时,图形外的区域也应记为一个区域。 常见的控制流基本结构包括顺序结构、选择结构、while循环结构及case多分支结构等。这4种结构的程序示例及控制流程图分别如图4.1~4.4所示。 图4.2选择结构 图4.3while循环结构 可依据源程序直接绘制程序控制流图,也可依据已有的程序流程图绘制对应的控制流图。值得提醒的是,程序流程图的判定中,条件表达式若为or、and等逻辑运算符连接而成的复合条件表达式,则将程序流程图转换为控制流图时,需将复合条件的判定拆分为一系列仅有单个条件的嵌套的判定,如图4.5所示。 图4.4case多分支结构 图4.5复合条件判定的拆分 2) 依据画出的控制流图计算程序环路复杂度 什么是程序环路复杂度?程序环路复杂度即圈复杂度,它是一种判定程序逻辑复杂性的定量度量方式,常用图4.6控制流图示例 于计算程序的基本独立路径数。程序环路复杂度的具体计算方式有如下3种。 前提说明: 控制流图G的程序环路复杂度为V(G),边的数量为E,结点的数量为N,判定结点的数量(即分支结点的数量)为P。 计算方式1: V(G)=E-N+2; 计算方式2: V(G)=P+1; 计算方式3: V(G)=G中区域的数量。 以图4.6所示控制流图为例,计算程序环路复杂度如下。 计算方式1: V(G)=E-N+2=16-12+2=6。 计算方式2: V(G)=P+1=5+1=6,其中结点2、3、5、6、9为判定结点。 计算方式3: V(G)=G中区域的数量=6。 3) 找出控制流图中的各条独立路径 什么是独立路径?独立路径是指从程序的开始至结束的多次执行中,每次至少引入一条新的、尚未执行过的语句,即每次至少要经历一条从未走过的弧。上述得出的V(G)值恰恰等于程序的独立路径条数。例如,图4.6中的独立路径条数为6,具体路径如下。 路径1: 1—2—9—10—12。 路径2: 1—2—9—11—12。 路径3: 1—2—3—9—10—12。 路径4: 1—2—3—4—5—8—2…… 路径5: 1—2—3—4—5—6—8—2…… 路径6: 1—2—3—4—5—6—7—8—2…… 4) 设计覆盖各条独立路径的测试用例,并将预期结果汇总成表格 此步骤中,仅需结合找出的基本路径,分别设计覆盖此路径的程序输入值及预期结果即可。例如,针对路径2而言,输入值为“score[ 1 ]=-1”,相应预期结果为“average=-1,其他量保持初值”;同理,设计用例分别覆盖其他5条路径。 注意:在全国计算机技术与软件专业技术资格考试的软件评测师考试中,基本路径测试法往往占有绝对的分量,是软件评测人员的必备知识。 下面以软件评测师考试中的典型真题为例,进行基本路径测试法的应用讲解。 3. 实验任务 说明: 以下源程序的代码由C语言书写,能根据指定的年、月计算当月所含天数。 源程序:int GetMaxDay(int year, int month) { int maxday=0; if(month>=1 && month<=12) { if(month==2) { if(year % 4==0) { if(year % 100==0) { if(year % 400==0) maxday=29; else maxday=28; } else maxday=29; } else maxday=28; } else { if(month==4 || month==6 || month==9 || month==11) maxday=30; else maxday=31; } } return maxday; }(1) 画出以上源程序的控制流图。 (2) 计算所画控制流图的程序环路复杂度V(G)。 (3) 假设year的取值范围是1000