一、实验目的
掌握基于覆盖理论与基本路径的基本白盒测试方法和实践
二、实验要求
运用逻辑覆盖测试的覆盖准则设计被测程序的测试用例,并运行测试用例检查程序的正确与否,给出程序缺陷小结。
三、实验内容
根据各位同学自己的被测程序,分别作出各类白盒测试技术的用例设计和相应的Junit脚本。
所有的覆盖的技术:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、组合覆盖、路径覆盖,基本路径测试方法。
包括的内容有:
1) 被测原代码
2)依据覆盖技术,测试用例列表:
3)相应Junit测试脚本、执行结果
4)给出测试参数化和打包测试的脚本,并生成执行结果
四、实验步骤
1) 被测原代码
1 import java.text.DecimalFormat; 2 import java.util.Scanner; 3 public class TestPractice { 4 public static void main(String[] args) { 5 6 Scanner input = new Scanner(System.in); //输入 7 while(true) 8 { 9 System.out.println("请分别输入三种手机配件的销售情况:"); 10 int headphone_num; 11 int shell_num; 12 int protector_num; 13 try { 14 //输入耳机、手机壳、手机贴膜的数量 15 System.out.print("请输入耳机的销售数量:"); 16 headphone_num=Integer.parseInt(input.next()); 17 System.out.print("请输入手机壳的销售数量:"); 18 shell_num=Integer.parseInt(input.next()); 19 System.out.print("请输入手机贴膜的销售数量:"); 20 protector_num=Integer.parseInt(input.next()); 21 if(headphone_num>0&&shell_num>0&&protector_num>0) 22 { 23 TestPractice testPractice = new TestPractice(); 24 //调用Commission方法 25 double commissiom = testPractice.Commission(headphone_num, shell_num, protector_num); 26 DecimalFormat df=new DecimalFormat("#.0"); //限制输出佣金的小数点后的位数 27 System.out.println("佣金:"+df.format(commissiom)); //输出佣金 28 } 29 else{ 30 System.out.println("输入的数量不满足要求!请重新输入!"); 31 } 32 continue; 33 } catch (Exception e) { 34 System.out.println("出现异常:"+e); 35 } 36 } 37 } 38 39 //计算佣金 40 double Commission(int headphone,int shell,int protector) 41 { 42 double commission=0; //初始化佣金为0 43 int headphone_price=80; //耳机单价80; 44 int shell_price=10; //手机壳单价10; 45 int protector_price=8; //手机贴膜单价8; 46 int total=headphone*headphone_price+shell*shell_price+protector*protector_price; 47 if(total<1000&&total>0){ //销售额不足1000提取10%佣金 48 commission=total*0.1; 49 }else if(total<=1800){ //销售额在1000-1800,提取15%佣金 50 commission=total*0.15; 51 }else { //销售额大于1800提起20%佣金 52 commission=total*0.2; 53 } 54 return commission; 55 } 56 }
2)依据覆盖技术,测试用例列表:
(1)基本路径测试
a.控制流程图
b.节点压缩
程序图节点 |
DD-路径 |
13 |
A |
33,34 |
B |
15 |
C |
16,17,18,19,20,21 |
D |
30 |
E |
23,24,25,40,46,47 |
F |
48 |
G |
49 |
H |
50 |
I |
52 |
J |
54,26,27 |
K |
c.压缩的控制流程图
c.所有DD路径
DD路径编号 |
路径 |
1 |
AB |
2 |
ACDE |
3 |
ACDFGK |
4 |
ACDFGHIK |
5 |
ACDFGHJK |
d.测试用例
用例编号 |
输入 |
覆盖路径编号 |
预期结果 |
实际结果 |
通过 |
时间 |
1 |
1a,12,12 |
1 |
出现异常:java.lang.NumberFormatException: For input string: "1a" |
出现异常:java.lang.NumberFormatException: For input string: "1a" |
√ |
2017/4/13 |
2 |
0,0,0 |
2 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/13 |
3 |
8,9,10 |
3 |
81.0 |
81.0 |
√ |
2017/4/13 |
4 |
20,5,5 |
4 |
253.5 |
253.5 |
√ |
2017/4/13 |
5 |
20,21,22 |
5 |
397.2 |
397.2 |
√ |
2017/4/13 |
(2)覆盖技术测试
覆盖方式 |
用例编号 |
输入 |
期待结果 |
实际结果 |
通过 |
时间 |
语句覆盖 |
1 |
10,10,10 |
98.0 |
98.0 |
√ |
2017/4/11 |
语句覆盖 |
2 |
0,0,0 |
“输入的数量不满足要求!请重新输入!” |
“输入的数量不满足要求!请重新输入!” |
√ |
2017/4/11 |
语句覆盖 |
3 |
20,20,10 |
367.0 |
367.0 |
√ |
2017/4/11 |
判定覆盖 |
4 |
-5,5,0 |
“输入的数量不满足要求!请重新输入!” |
“输入的数量不满足要求!请重新输入!” |
√ |
2017/4/11 |
判定覆盖 |
5 |
1,1,1 |
9.8 |
9.8 |
√ |
2017/4/11 |
判定覆盖 |
6 |
20,10,10 |
267.0 |
267.0 |
√ |
2017/4/11 |
判定覆盖 |
7 |
2147483647,2147483647,2147483647 |
210453397406, |
-14,7 |
× |
2017/4/11 |
条件覆盖 |
8 |
9,10,10 |
90.0 |
90.0 |
√ |
2017/4/11 |
条件覆盖 |
9 |
23.0,23,23 |
出现异常:java.lang.NumberFormatException: For input string: "23.0" |
出现异常:java.lang.NumberFormatException: For input string: "23.0" |
√ |
2017/4/11 |
条件覆盖 |
10 |
30,-10,-10 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
11 |
1w,1,1 |
出现异常:java.lang.NumberFormatException: For input string: "1w" |
出现异常:java.lang.NumberFormatException: For input string: "1w" |
√ |
2017/4/11 |
组合覆盖 |
12 |
5,5,5 |
49.0 |
49.0 |
√ |
2017/4/11 |
组合覆盖 |
13 |
30,20,-10 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
14 |
30,-10,10 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
15 |
-1,300,10 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
16 |
-1,-1,300 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
17 |
-1,300,-1 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
组合覆盖 |
18 |
300,-1,-1 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
路径覆盖 |
19 |
-1,-1,-1 |
输入的数量不满足要求!请重新输入! |
输入的数量不满足要求!请重新输入! |
√ |
2017/4/11 |
路径覆盖 |
20 |
1,2,3 |
12.4 |
12.4 |
√ |
2017/4/11 |
路径覆盖 |
21 |
15,10,10 |
207.0 |
207.0 |
√ |
2017/4/11 |
路径覆盖 |
22 |
1,1,2147483647 |
3435973853.2 |
8.200000000000001 |
× |
2017/4/11 |
3)相应Junit测试脚本、执行结果
a.语句覆盖
package one; import static org.junit.Assert.*; import org.junit.Test; public class StatementCoverageCase { @Test public void testCommissionStatement2() { assertEquals(98.0, new TestPractice().Commission(10, 10, 10),0.0); } @Test public void testCommissionStatement3() { assertEquals(376.0, new TestPractice().Commission(20, 20, 10),0.0); } }
b.判定覆盖
package one; import static org.junit.Assert.*; import org.junit.Test; public class DecisionCoverageCase { @Test public void testCommissionDecision1() { assertEquals(9.8, new TestPractice().Commission(1, 1, 1),0.0); } @Test public void testCommissionDecision2() { assertEquals(267.0, new TestPractice().Commission(20, 10, 10),0.0); } @Test public void testCommissionDecision3() { assertEquals(210453397406.0, new TestPractice().Commission(2147483647, 2147483647, 2147483647),0.0); } }
c.条件覆盖
ackage one; import static org.junit.Assert.*; import org.junit.Test; public class ConditionCoverageCase { @Test public void testCommissionCondition1() { assertEquals(90.0, new TestPractice().Commission(9, 10, 10),0.0); } }
d.组合覆盖
package one; import static org.junit.Assert.*; import org.junit.Test; public class PortfolioCoverageCase { @Test public void testCommissionPortfolio1() { assertEquals(49.0, new TestPractice().Commission(5,5,5),0.0); } }
e.路径覆盖
package one; import static org.junit.Assert.*; import org.junit.Test; public class PathCoverageCase { @Test public void testCommissionPath1() { assertEquals(12.4, new TestPractice().Commission(1, 2, 3),0.0); } @Test public void testCommissionpath2() { assertEquals(207.0, new TestPractice().Commission(15, 10, 10),0.0); } @Test public void testCommissionpath3() { assertEquals(3435973853.2, new TestPractice().Commission(1,1,2147483647),0.0); } }
4)给出测试参数化和打包测试的脚本,并生成执行结果
package one; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class ParameterCoverageCase { private int a; private int b; private int c; private double result; public ParameterCoverageCase(int a,int b,int c,double result){ this.a=a; this.b=b; this.c=c; this.result=result; } //初始化参数 @Parameters public static Collection TestData() { return Arrays.asList(new Object[][] { {10,10,10,98.0}, {1,1,1,9.8}, { 20,10,10,267.0 }, { 2147483647, 2147483647, 2147483647,210453397406.0 }, {9,10,10,90.0}, {5,5,5,49.0}, {1,2,3,12.4}, {15,10,10,207.0}, {1,1,2147483647,3435973853.2}, }); } @Test public void Tset1(){ assertEquals(result,new TestPractice().Commission(a, b, c),0.0); } }
package one; import org.junit.runner.RunWith; import org.junit.runners.Suite; @RunWith(Suite.class) @Suite.SuiteClasses({ConditionCoverageCase.class,DecisionCoverageCase.class, PathCoverageCase.class,PortfolioCoverageCase.class,StatementCoverageCase.class }) public class PackageCoverageCase { }
4、测试小结:
(1)测试找到的缺陷清单
缺陷编号 |
用例编号 |
期望结果 |
实际结果 |
差别分析 |
1 |
7 |
210453397406.0 |
-14,7 |
数值溢出 |
2 |
22 |
3435973853.2 |
8.200000000000001 |
精度丢失 |
(2)对源代码的修改建议:最初要求的方法为float commission (int headphone, int shell, int protector),建议修改,不用将double的返回值再通过
DecimalFormat("#.0")处理;建议对输入判断处理能封装为一个方法;对于输入int型数值最大范围有个处理,还有total值最大范围处理。
(3)测试总结与心得体会:DD路径图可以将程序流程简化,几个分支,几条线更加清晰,对用例编写有好处;但是简化后,对程序内部数据处理就忽视了,如果在一条路径里,数据经过多次处理,出错的话,需找错误点会比较慢比较不容易。