结对编程2——单元测试
本人学号:201421123083 小伙伴:201421123067
项目地址:https://git.oschina.net/HuanWong/JunitTest
a.需求分析
对于一个程序来说不仅要可用,还应该追求稳定,所以应该对程序的各部分功能进行测试,尽量修复bug。本文进行的测试针对前期已实现的分数计算模块,利用Juint4测试其中分数生成,加减乘除,求最大公约数、求最小公倍数等方法在各种可能情况下能否正常工作。基于可能的结果,可选的测试情况包括:
- 测试正常情况下,计算的结果是否正确;
- 测试代码中对于题目条件约束是否有效,如保证减法结果不出现负数,除数不为零等。
- 测试计算类对于各种参数的支持,主要测试程序的输入输出。
其中该如何测试,什么需要测试要结合实际程序的思路及编写方法。
b.实际测试
1.Fraction类,测试createFraction、GCD、LCM方法
- createFraction方法随机生成一个真分数,故要求不允许分子大于或等于分母,还要禁止出现分母为零的情况。故在Junit测试类的createFractionTest方法中多次调用createFraction方法检查结果。
测试用例:
@Test
public void testCreateFraction() {
for(int i=0;i<20;i++){
num=Fraction.createFraction();
System.out.println(num[0]+"/"+num[1]);
}
}
多次运行检查结果均符合要求:
- GCD与LCM类求两数最大公约数与最小公倍数,测试准确性,还要保证正确处理数值为零的情况。
测试用例:
@Test
public void testGCD() {
int x;
x = Fraction.GCD(9, 6);System.out.println(x);
x = Fraction.GCD(1, 5);System.out.println(x);
x = Fraction.GCD(28, 6);System.out.println(x);
x = Fraction.GCD(49, 21);System.out.println(x);
x = Fraction.GCD(0, 0);System.out.println(x);
x = Fraction.GCD(1, 0);System.out.println(x);
x = Fraction.GCD(0, 1);System.out.println(x);
System.out.println("-----分割线-----");
}
@Test
public void testLCM() {
int x;
x = Fraction.LCM(9, 6);System.out.println(x);
x = Fraction.LCM(1, 5);System.out.println(x);
x = Fraction.LCM(28, 6);System.out.println(x);
x = Fraction.LCM(49, 21);System.out.println(x);
x = Fraction.LCM(0, 0);System.out.println(x);
x = Fraction.LCM(1, 0);System.out.println(x);
x = Fraction.LCM(0, 1);System.out.println(x);
System.out.println("-----分割线-----");
}
运行结果:
GCD与LCM无法处理参数出现零的情况,因为忽略了有可能计算结果的分子为零,在公约数化简时会出错的情况而跳过了处理。依照实际程序思路,在出现0时可以在GCD中返回1,LCM中返回-1来处理,也可以在计算结果中判断分子是否为零避免传入参数0。这里选择前者,修改GCD与LCM:
public static int GCD(int m, int n) {//辗转相除法求最大公约数
if(m==0||n==0){
return -1;
}
while (true) {
if ((m = m % n) == 0)
return n;
if ((n = n % m) == 0)
return m;
}
}
public static int LCM(int m, int n){
if(GCD(m,n)==-1){
return 1;
}
return m*n/GCD(m,n);
}
运行测试:
修改后结果达到预期。
2.CreateFracQuestion类,测试具体运算类运行情况。
测试用例:
static int[] fa1={1,2};
static int[] fa2={3,4};
static String[] arr={"分子","分母"};
int gbs=Fraction.LCM(fa1[1],fa2[1]);
结果:
改变fa1与fa2值进行测试,计算结果正常,发现减法出现加号,查看方法代码发现输出字符串"("+fa2[0]+"/"+fa2[1]+")+("+fa1[0]+"/"+fa1[1]+")= "+"\t\t"
中“-”写成了“+”导致错误。
改正符号测试特殊值,分别令fa1={0,2};fa2={3,4};
能处理计算结果为0的情况,这也验证了前面修改GCD与LCM方法达到效果。反复测试,发现结果均正常。
由于未做处理,传入分母为0依然会出错,考虑程序运行时传入分数为testCreateFraction方法生成,前面已验证testCreateFraction方法不会产生这种情况,故跳过处理(这样不好不好)。
3.模拟程序测试
结合两个类的功能,利用随机生成分数再生成算式来模拟程序运行。
测试用例:
static int[] fa1=Fraction.createFraction();
static int[] fa2=Fraction.createFraction();
static String[] arr={"分子","分母"};
int gbs=Fraction.LCM(fa1[1],fa2[1]);
测试结果:
重复运行程序结果皆正常,测试结束。
代码覆盖率:
FractionTest:
craeteFracQuestion:
c. 小结与感受:
通过测试,我们能够有效的发现程序计算模块的问题,并且给予改进。
1.使用junit做测试目的是尽量早的发现程序的bug,我们通过测试,能够发现各模块内部可能存在的各种差错,为我们找出bug节省了更多的时间。
2.使用junit4之后,我发现测试变得更加简单了,我们可以通过junit4调用各类中的方法,有效的发现该类出现的bug,并且加以改进。
d.体会
1.良好的设计:代码需讲究模块化,如若没有模块化,例如我们本次的测试,如若发现bug,代码进行修改时,就得牵一发而动全身,这会使我们修改的非常痛苦。并且当我们阅读我们的代程序时,模块化能让我们更加清楚快速的看懂我们写的是什么,而不是冗长的一段程序,使我们阅读时非常吃力。
2.编码规范:我们在编码时,有考虑到一些编码上的规范,例如一些文件、类、方法、变量名的命名,编写时括号的对应,编码的格式等,这使得我们再次看我们的程序时,能够较好的理解。
3.必要的注释:在时隔一周再次看我们的程序,感到有些陌生,会有些看不懂,然后对代码加上适当的的注释使得我们能够一看就知道该方法是做什么,加快了我们的理解。
结对过程:
先熟悉之前的代码,参考助教提供的事例进行学习、讨论。由于我们的程序已经有模块的划分,因此对原有类进行了稍加改造后我们开始进行模块测试阶段。首先对Fraction进行测试、改进、提交;其次,对CreateFracQuestion类进行测试、改进、提交;最后我们一起讨论编写博客。
Photo:
PSP
PSP2.1 | Personal Software Process Stages | Time Senior Student | Time |
---|---|---|---|
Planning | 计划 | ||
· Estimate | 估计这个任务需要多少时间 | 7h | 8h |
Development | 开发 | ||
· Analysis | 需求分析 (包括学习新技术) | 0.6h | 0.5h |
Design Spec | 生成设计文档 | ||
· Design Review | 设计复审 | ||
· Coding Standard | 代码规范 | 0.3h | 0.2h |
· Design | 具体设计 | ||
· Coding | 具体编码 | 0.5h | 0.5h |
· Code Review | 代码复审 | 0.6h | 0.7h |
· Test | 测试(自我测试,修改代码,提交修改) | 2.5h | 2.5h |
Reporting | 报告 | 2h | 2.5h |
· | 测试报告 | ||
· | 计算工作量 | ||
· | 并提出过程改进计划 |