一、实验目的
掌握基于覆盖理论与基本路径的基本白盒测试方法和实践
二、实验要求
运用逻辑覆盖测试的覆盖准则设计被测程序的测试用例,并运行测试用例检查程序的正确与否,给出程序缺陷小结。
三、实验内容
根据各位同学自己的被测程序,分别作出各类白盒测试技术的用例设计和相应的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路径图可以将程序流程简化,几个分支,几条线更加清晰,对用例编写有好处;但是简化后,对程序内部数据处理就忽视了,如果在一条路径里,数据经过多次处理,出错的话,需找错误点会比较慢比较不容易。