1.控制流图:
基础:根据源代码构建控制流图时需注意: 控制流图仅仅关注逻辑走向,而不关注中间的每一条语句的具体含义。 在顺序结构中,尽管可能包含了多条语句(语句块),但是在控制流图仅仅用一个节点表示。
控制流程图例子
2.基本路径
请为程序模块Function1
(1)画出程序控制流图,计算控制流图的环路复杂度
(2)导出基本路径
(3)设计基本路径覆盖测试用例
程序模块Function1代码如下
1 public int Function1(int num, int cycle, boolean flag)
2 {
3 int ret = 0;
4 while( cycle > 0 )
5 {
6 if( flag == true )
7 {
8 ret = num - 10;
9 break;
10 }
11 else
12 {
13 if( num%2 ==0 )
14 {
15 ret = ret * 10;
16 }
17 else
18 {
19 ret = ret + 1;
20 }
21 }
22 cycle--;
23 }
24 return ret;
25 }
作图注意点:有唯一出入结点
圈复杂度:
11(边数)-9(节点数)+2=4
基本路径:
A:1,2,9
B:1,2,3,4,8,2,9
C:1,2,3,5,6,8,2,9
D:1,2,3,5,7,8,2,9
3、下图的简单路径和主路径有:
(简单路径:除了起点和终点外,路径上的节点出现不多于一次)
(主路径:不是其他任何简单路径的子路径的简单路径。)
简单路径:
[1,2,4,1], [1,3,4,1], [2,4,1,2], [2,4,1,3], [3,4,1,2], [3,4,1,3], [4,1,2,4], [4,1,3,4],
[1,2,4], [1,3,4], [2,4,1], [3,4,1], [4,1,2], [4,1,3],
[1,2], [1,3], [2,4], [3,4], [4,1],
[1], [2], [3], [4]
主路径:
[1,2,4,1], [1,3,4,1], [2,4,1,2], [2,4,1,3], [3,4,1,2], [3,4,1,3], [4,1,3,4], [4,1,2,4]
4、求下图的简单路径和主路经,并求覆盖主路径的其他测试路径集:
求覆盖主路径的其他测试路径集:1、列举覆盖所有节点的路径集P 例如:广度搜索每个起始节点到其它节点的路径 2、将路径集P扩展为测试路径集TP 对不含终止节点的路径p,将其拓展到终止节点3、 根据TP生成覆盖所有主路径的测试路径集 对不被TP覆盖的主路径,根据TP拓展为测试路径 去除冗余测试路径
5、利用条件/判定方法设计测试用例
a)判定: If ( x>0 OR y>0) If (x<10 AND y<10)
测试用 例编号 | x | y | 条件x>0 | 条件y>0 | 条件 x<10 | 条件 y<10 |
case1 | 20 | 20 | Y | Y | N | N |
case2 | -2 | -2 | N | N | Y | Y |
b)三角形判定问题的案例,有程序段P2如下:
if ((a<b+c) && (b<a+c) && (c<a+b)) is_Triangle = true;
else is_Triangle = false;
对该程序段进行测试时,要求满足条件/判定覆盖。
a | b | c | a<b+c | b<a+c | c<a+b | (a<b+c) && (b<a+c) && (c<a+b) |
1 | 1 | 1 | Y | Y | Y | Y |
1 | 2 | 3 | Y | Y | N | N |
3 | 1 | 2 | N | Y | Y | N |
2 | 3 | 1 | Y | N | Y | N |
6.利用条件组合方式进行用例设计
例1,对于程序段P1,两个判断 If ( x>0 OR y>0) If (x<10 AND y<10) 每个判定中有两个条件,而两个条件可能的组合情况有4种。 ( x>0 OR y>0) 4种组合; (x<10 AND y<10) 4种组合;
测试编号 | x | y | 第1个判定 | 第2个判定 | ||
条件x>0 | 条件 y>0 | 条件 x<10 | 条件y<10 | |||
case12 | 50 | 50 | Y | Y | N | N |
case13 | -5 | -5 | N | N | Y | Y |
case14 | 50 | -5 | Y | N | N | Y |
case15 | -5 | 50 | N | Y | Y |
例2:
请为以下程序段设计测试用例集,要求满足条件组合覆盖
public class Triangle {
protected long lborderA = 0;
protected long lborderB = 0;
protected long lborderC = 0;// Constructor
public Triangle(long lborderA, long lborderB, long lborderC) {
this.lborderA = lborderA;
this.lborderB = lborderB;
this.lborderC = lborderC;
}public boolean isTriangle(Triangle triangle) {
boolean isTriangle = false;
// check boundary
if (triangle.lborderA > 0 && triangle.lborderB > 0 && triangle.lborderC > 0 )
// check if subtraction of two border larger than the third
if ((triangle.lborderA-triangle.lborderB) < triangle.lborderC
&& (triangle.lborderB-triangle.lborderC) < triangle.lborderA
&& (triangle.lborderC-triangle.lborderA) < triangle.lborderB)
{isTriangle = true; }
return isTriangle;
}
}
7、利用修正条件/判定覆盖设计测试用例:
(要真正测试每个简单条件的结果,则该条件应该能够影响整个判定谓词的取值 )
例如 判定表达式 Z= (A or B) and (C or D) 其中A、B、C、D是简单条件。 测试用例2和10覆盖条件A。 找出覆盖B,C,D的测试用例。
如何求满足MC/DC的测试用例集? (1)列出条件的全组合。 (2)找出独立影响对。 (3)找出最小测试用例集。
例1: 考虑复合条件表达式 A and B,其中A、B为简单条件。
测试用例编号 | A | B | 表达式 |
1 | T | T | T |
2 | T | F | F |
3 | F | T | F |
4 | F | F | F |
例2: 考虑复合条件表达式(A and B) or C,其中A、B、C为简单条件。
测试用例编号 | A | B | C | 表达式 |
1 | T | T | T | T |
2 | T | T | F | T |
3 | T | F | T | T |
4 | T | F | F | F |
5 | F | T | T | F |
6 | F | T | F | F |
7 | F | F | T | F |
8 | F | F | F | F |
比对不同的行,找出独立影响输出的测试用例。
例子3:根据下列流程图设计满足MC/DC覆盖的测试数据。
8、循环的测试
基本的简单循环
对基本的简单循环进行测试的方法一般采用循环边界条件测试法 相当于对循环次数变量进行边界值测试,一般覆盖 7 个边界值点。
设 i 为实际循环次数,n 是最大循环次数, 那么测试用例应包括: 直接跳过循环体,让i=0; 只执行一遍循环体,让i=1; 执行两遍循环体,让i=2; 执行m遍循环体(2< m < n-1) ; 执行n -1遍循环体,让i=n-1; 正好执行 n 遍循环体,让i=n; 超出最大循环次数。
题目:
// 被测程序 int My_Sum(int j){
int i=1,s=0,a=100;
while (i<=j and i<=a)
{ s=s+i; i=i+1; }
return s; }
答:CASE 1:j=0 实际循环 0 次
CASE 2:j=1 实际循环 1 次
CASE 3:j=2 实际循环 2 次
CASE 4:j=50 实际循环 50 次
CASE 5:j=99 实际循环 99 次
CASE 6:j=100 实际循环 100次
CASE 7:j=101 实际循环 100次 且此时i=101超出最大循环次数
复合循环结构测试
测试嵌套循环的方法为: 从最内层测试开始,其它层的循环变量固定; 按照简单循环的测试方法测试最内层的循环体; 向外扩展循环体,测试下一个循环:外层循环变量固定;内层嵌套的循环体也固定; 继续本步骤直到所有的循环体均测试完毕。
测试串接循环的方法为: 如果相连接的循环体互相独立,那么按照简单循环测试每一个循环体即可。 如果相连接的循环体 1 的循环变量的最终结果是循环体 2 循环变量的初始值,那么可采用针对嵌套循环的方法来测试。
9、程序插桩
请对以下程序进行插桩,显示循环执行的次数
public class GCD {
public int getGCD(int x,int y){
if(x<1||x>100)
{
System.out.println("参数不正确!");
return -1;
}if(y<1||y>100)
{
System.out.println("参数不正确!");
return -1;
}int max,min,result = 1;
if(x>=y)
{
max = x;
min = y;
}
else
{
max = y;
min = x;
}for(int n=1;n<=min;n++)
{
if(min%n==0&&max%n==0)
{
if(n>result)
result = n;
}
}System.out.println("最大公约数为:"+result);
return result;
}
}
答案:
public class ceshi {
int count=0;
public static void main(String[] args) {ceshi ceshi=new ceshi();
int x=4;
int y=10;
ceshi.getGCD(x,y);
}public int getGCD(int x,int y){
if(x<1||x>100)
{
System.out.println("参数不正确!");
return -1;
}if(y<1||y>100)
{
System.out.println("参数不正确!");
return -1;
}int max,min,result = 1;
if(x>=y)
{
max = x;
min = y;
}
else
{
max = y;
min = x;
}for(int n=1;n<=min;n++)
{
count++;
if(min%n==0&&max%n==0)
{
if(n>result)
result = n;
}
}System.out.println("最大公约数为:"+result);
System.out.println("count:"+count);
return result;
}
}
10、补充:白盒测试方法运用示例
步骤:运用基本路径或主路径测试方法设计相关测试用例, 运用逻辑覆盖测试方法设计相关测试用例, 运用循环测试方法设计相关测试用例 ,综合上面三个结果,并去除冗余, 根据程序的特点增加相应的测试用例
例子:
请为以下程序段设计测试用例集,要求分别满足语句覆盖、判定覆盖、条件覆盖、条件/判定覆盖覆盖、条件组合覆盖。
public int do_work(int A,int B){
int x=0;
if((A>4) && (B<9))
{ x = A-B;}
if( A==5 && B>28 )
{ x= A+B;}
return x;
}
11、等价类划分法
划分等价类(核心工作、也是最有挑战性的); 给每个等价类设置一个不同的编号; 编写一个新的测试用例,使其尽可能多地覆盖尚未覆盖的有效等价类,重复这一步直到所有有效等价类均被测试用例所覆盖;当所有的有效等价类都被覆盖之后,进入下一个步骤。 编写一个新的测试用例,使其只覆盖一个无效等价类,重复这一步,直到所有无效等价类均被覆盖。
例1:
在三角形问题中,输入条件要求:
● 类型:整数; ● 个数:三个数; ● 取值范围:在1到100之间
例2:练习--报表日期
设某公司要打印2001~2005年的报表,其中报表日期为6位数字组成,其中,前4位为年份,后两位为月份。
例3:
等价类测试示例:NextDate问题 NextDate(月,日,年)是三个变量的函数。函数返回输入日期的下一个日期。变量月份、日期和年都是整数值,且满足下面的条件:1<=月份<=12,1<=日期<=31,1900<=年<=2060
12、采用边界值设计测试用例
例:三角形问题采用边界值分析法 假设输入三条边的合法范围是 [1,100],采用一般边界值
若增加健壮性边界测试,在上表基础增加测试用例:
例4:
某种信息加密代码由三部分组成,这三部分的名称和内容分别是加密类型码:空白或三位数字;前缀码 :非’0’或’1’开头的三位数;后缀码 :四位数字。假定被测试的程序能接受一切符合上述规定的信息加密代码,拒绝所有不符合规定的信息加密代码,
试用等价类划分法,分析它所有的等价类,并设计测试用例。
参考答案:
13决策表法
1.列出所有的条件桩和动作桩,确定规则的条数 例如
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
问题 | 你觉得疲倦吗? | ||||||||
你对书中内容感兴趣吗? | |||||||||
书中内容使你胡涂吗? | |||||||||
建议 | 请回到本章开头重读 | ||||||||
继续读下去 | |||||||||
跳到下一章去读 | |||||||||
停止阅读,请休息 |
2、填入条件的不同取值组合; 3、填入具体动作,得到初始判定表;
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | |
问题 | 你觉得疲倦吗? | Y | Y | Y | Y | N | N | N | N |
你对书中内容感兴趣吗? | Y | Y | N | N | Y | Y | N | N | |
书中内容使你胡涂吗? | Y | N | Y | N | Y | N | Y | N | |
建议 | 请回到本章开头重读 | √ | √ | ||||||
继续读下去 | √ | √ | |||||||
跳到下一章去读 | √ | √ | |||||||
停止阅读,请休息 | √ | √ |
4、化简,合并一些具有相同动作的相似规则。 化简就是将规则合并。如果有两条或多条规则具有相同的动作,并且它们的条件项很相似,则可以考虑能否把这些规则合并为1条规则,从而使得判定表得到简化。 例右图,可以把这两条规则合并成 1条规则,无关的条件其取值可用 横线填充。
练习1:
假设某程序规格要求如下:“……对功率大于50马力并且维修记录不全,或者已运行10年以上的机器,应给予优先的维修处理……”,假定,“维修记录不全”和“优先维修处理”均已在别处有更严格的定义。
确定规则的条数、列出所有的条件桩和动作桩:
填入条件项和动作顶,得到初始决策表 :
合并相似规则: 规则1、2可以合并;5、7可以合并;6、8可以合并。
根据最终决策表的5条规则,设计5个测试用例。
练习2
三角形问题示例:
条件、动作、规则条数?(假设输入数据均合法)
例3
NextDate问题示例 ;
NextDate(月,日,年)是三个变量的函数。函数返回输入日期的下一个日期。变量月份、日期和年都是整数值,且满足下面的条件:1<=月份<=12,1<=日期<=31,1900<=年<=2060
解答:
条件桩 ? 输入条件细分等价类 使用扩展项决策表
动作桩 ? 细分动作 日期增1,日期复位为1,月份增1,月份复位为1,年份增1,不可能的日期
测试用例
规则1:测试输入 = (2007,7,19), 预期结果 = “2007-7-20”
规则2:测试输入 = (2007,7,31), 预期结果 = “2007-8-1”
规则3:测试输入 = (2007,9,25), 预期结果 = “2007-9-26”
规则4:测试输入 = (2007,9,30), 预期结果 = “2007-10-1”
规则5:测试输入 = (2007,11,31),预期结果 = “日期输入错误”
规则6:测试输入 = (2000,2,15), 预期结果 = “2000-2-16”
规则7:测试输入 = (2000,2,29), 预期结果 = “2000-3-1”
规则8:测试输入 = (2000,2,30), 预期结果 = “日期输入错误”
规则9:测试输入 = (2007,2,15), 预期结果 = “2007-2-16”
规则10:测试输入 = (2007,2,28), 预期结果 = “2007-3-1”
规则11:测试输入 = (2007,2,29), 预期结果 = “日期输入错误”
规则12:测试输入 = (2006,12,16), 预期结果 = “2006-12-17”
规则13:测试输入 = (2006,12,31), 预期结果 = “2007-1-1”
14 因果图
在因果图中,通常: 用 Ci 表示原因,置于图的左部; 用 Ei 表示结果,置于图的右部。 Ci和Ei均可取值0或1,0 表示某状态不出现,1表示某状态出现。原因和结果之间以直线连接。
(1)关系
(2)约束
各个输入条件相互之间还可能存在某种关系,称为约束。例如:某些输入条件不可能同时出现。 输出状态之间也往往存在约束。 在因果图中,用特定的符号标明这些约束。
A.输入条件的约束有以下4类: ① E 约束(互斥):表示不同时为1,即a,b,c中至多只有一个1; ② I 约束(包含):表示至少有一个1,即a,b,c中不同时为0; ③ O 约束(唯一):表示a,b,c中有且仅有一个1;④ R 约束(要求):表示若a=1,则b必须为1。即不可能a=1且b=0;例如,手机号与验证码
B.输出条件约束类型 输出条件的约束只有 M 约束(屏蔽):若结果 a是1,则结果 b 强制为0。
采用因果图法设计测试用例的步骤,
一个文件管理系统的一段规格说明:“文件第一列字符必须A或B,第二列字符必须是数字,在此情况下文件被更新。如果第一列字符不正确,则提示错误信息“ERR1”;如果第二列字符不正确,则提示错误信息“ERR2”。
解:
原因:1——第一个字符是A 2——第一个字符是B 3——第二个字符是数字
结果: 70——文件进行更新 71——提示信息ERR1 72——提示信息ERR2
文件第一列字符必须A(原因1)或B(原因2),第二列字符必须是数字(原因3),在此情况下文件被更新(结果70)。 如果第一列字符不正确,则提示错误信息“ERR1”(结果71); 如果第二列字符不正确,则提示错误信息“ERR2”(结果72)。
应用因果图判定表的思想设计测试用例。
有一个处理单价为5角钱的饮料自动售货机软件。其规格说明如下: 若投入5角钱,按下〖橙汁〗或〖啤酒〗的按钮,则相应的饮料就送出来。 若投入1元钱的硬币,按下〖橙汁〗或〖啤酒〗的按钮: 若售货机没有零钱找,则一个显示〖零钱找完〗的红灯亮,这时在投入1元硬币并按下按钮后,饮料不送出来而且1元硬币也退出来; 若有零钱找,则显示〖零钱找完〗的红灯灭,在送出饮料的同时退还5角硬币。
解答:
(1)分析这一自动售货机软件的规格说明,列出原因和结果。
原因: 1.售货机有零钱找 2.投入1元硬币 3.投入5角硬币 4.按下橙汁按钮 5.按下啤酒按钮
结果: 1.售货机〖零钱找完〗灯亮 2.退还1元硬币 3.退还5角硬币 4.送出橙汁饮料 5.送出啤酒饮料
(2)画出因果图。
当因果图规模较大时,可以引入一些中间节点,表示处理的中间状态。本题的中间结点如下: 1. 投入1元硬币且按下饮料按钮 2. 已按下按钮(〖橙汁〗或〖啤酒〗) 3. 应当找5角零钱并且售货机有零钱找 4. 钱已付清
(3)在因果图中加上约束条件
(4) 把因果图转换成判定表
(5)根据判定表设计测试用例
在判定表中,阴影部分表示因违反约束条件的不可能出现的情况,应删去。第16列与第32列因什么动作也没做,也应删去。最后可根据剩下的16列,来设计测试用例。
15、测试脚本
试针对如下程序代码设计测试脚本。
public class GCD {
public int getGCD(int x,int y) {
if(x<1||x>100) {
System.out.println("数据超出范围!");
return -1;
}
if(y<1||y>100) {
System.out.println("数据超出范围!");
return -1;
}
int max,min,result = 1;
if(x>=y) {
max = x;
min = y;
}
else {
max = y;
min = x;
}
for(int n=1;n<=min;n++) {
if(min%n==0&&max%n==0) {
if(n>result)
result = n;
}
}
System.out.println("因数:"+result);
return result;
}
}
参考答案:
(1)设计测试脚本,对GCD类的getGCD方法实现语句覆盖测试。
public class GCD {
public void testDemo(){
int test1=getGCD(-1,100);
int test2=getGCD(2,1);
System.println.out(test1+ test2);
}
public int getGCD(int x,int y) {
if(x<1||x>100) {
System.out.println("数据超出范围!");
return -1;
}
if(y<1||y>100) {
System.out.println("数据超出范围!");
return -1;
}
int max,min,result = 1;
if(x>=y) {
max = x;
min = y;
}
else {
max = y;
min = x;
}
for(int n=1;n<=min;n++) {
if(min%n==0&&max%n==0) {
if(n>result)
result = n;
}
}
System.out.println("因数:"+result);
return result;
}
}
2)设计测试脚本,对GCD类的getGCD方法实现条件覆盖测试。
public class GCD {
public void testDemo(){
int test1=getGCD(-1,-1);
int test2=getGCD(100,100);
int test3=getGCD(2,1);
int test4=getGCD(1,2);
System.println.out(test1+ test2+ test3+ test4);
}
public int getGCD(int x,int y) {
if(x<1||x>100) {
System.out.println("数据超出范围!");
return -1;
}
if(y<1||y>100) {
System.out.println("数据超出范围!");
return -1;
}
int max,min,result = 1;
if(x>=y) {
max = x;
min = y;
}
else {
max = y;
min = x;
}
for(int n=1;n<=min;n++) {
if(min%n==0&&max%n==0) {
if(n>result)
result = n;
}
}
System.out.println("因数:"+result);
return result;
}
}
16、变异
请对以下代码段进行变异,变异规则为将 “++” 替换为 “–”,然后设计测试数据,能够测试发现所有的变异点。
public class zhengchu {
public String iszhengchu(int n) {
if(n<0||n>500) {
return "error";
}
int flag=0;
String note="";
if(n%3==0) {
flag++;
note=note+" 3";
}if(n%5==0) {
flag++;
note+=" 5";
}if(n%7==0) {
flag++;
note+=" 7";
}return "能被"+flag+"个数整除,"+note;
}
}
答案:
17、错误推测法
某登录界面包括一个用户名输入框和一个密码输入框,以及一个登录按钮,试采用错误推测法,举出10种常见问题或错误,并设计10个测试用例。
18、场景法
有一个在线购物网站系统,主要功能包括登录、商品选购、在线支付完成购物等。用户在使用这些功能时可能会出现各种情况,如账号不存在、密码错误、账户余额不足等。设目前该系统中仅有一个账号abc;密码为123;账户余额200;仅有商品A,售价均为50元,库存为15,商品B售价为50元,库存为0。
试采用场景法:分析画出事件流图,标注出基本流和备选流;分析生成测试场景。对每一个场景设计相应的测试用例。
参考答案:
19、正交表法
有一个“用户信息输入”界面如下图,输入项有3个:姓名、昵称、手机号码,状态有两个:填与不填。请采用正交实验法对其进行测试。
(1)请选择一个合适的正交表
(2)根据选定的正交表进行变量映射
(3)写出测试用例
参考答案: