实验五 单元测试
一、实验目的
1)掌握单元测试的方法
2) 学习XUnit测试原理及框架;
3)掌握使用测试框架进行单元测试的方法和过程。
二、实验内容与要求
1、了解单元测试的原理与框架
1.1 单元测试原理
单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。
单元测试的内容包括
模块接口测试、局部数据结构测试、路径测试、错误处理测试、边界测试
1.2 测试框架
xUnit是各种代码驱动测试框架的统称,这些框架可以测试 软件的不同内容(单元),比如函数和类。xUnit框架的主要优点是,它提供了一个自动化测试的解决方案。可以避免多次编写重复的测试代码。
底层是xUnit的framwork,xUnit的类库,提供了对外的功能方法、工具类、api等
TestCase(具体的测试用例)去使用framwork
TestCase执行后会有TestResult
使用TestSuite控制TestCase的组合
TestRunner执行器,负责执行case
TestListener过程监听,监听case成功失败以及数据结果,输出到结果报告
1.3 面向特定语言的,基于xUnit框架的自动化测试框架
Junit : 主要测试用Java语言编写的代码
CPPunit:主要测试用C++语言编写的代码
unittest , PyUnit:主要测试用python语言编写的代码
MiniUnit: 主要用于测试C语言编写的代
JUnit是一个开发源代码的Java测试框架,用于编写和运行可重复的测试。他是用于单元测试框架体系xUnit的一个实例(用于java语言)
Eclipse 集成了 JUnit,可以非常方便地编写 Test Case。Eclipse 自带了一个 JUnit 插件,不用安装就可以在项目中测试相关的类,并且可以调试测试用例和被测类。下面以实例说明,如何建立一个基于 JUnit4 的测试项目,对一个类当中的多个方法进行单元测试。
因为此次我们小组的测试代码设计是 java ,所以我们采用Eclipse自带的 JUnit 进行案例的测试。
2、结对编程的小组采用测试框架 对自己“结对编程”实验的程序模块(类)进行单元测试
1)源码
1 package sizeyusuan; 2 3 import java.util.*; 4 import java.io.BufferedReader; 5 import java.io.BufferedWriter; 6 import java.io.File; 7 import java.io.FileOutputStream; 8 import java.io.FileReader; 9 import java.io.FileWriter; 10 import java.io.IOException; 11 import java.io.OutputStreamWriter; 12 import java.io.PrintWriter; 13 import java.io.RandomAccessFile; 14 public class xiaoxuesheng { 15 private static Random random = new Random(); 16 public static int range; 17 public static String reductionofFraction(int a, int b) {// 分数约分,用于计算结果 18 int y = 1; 19 for (int i = a; i >= 1; i--) { 20 if (a % i == 0 && b % i == 0) { 21 y = i; 22 break; 23 } 24 } 25 int z = a / y;// 分子 26 int m = b / y;// 分母 27 if (z == 0) { 28 return "0"; 29 } 30 if(m==1) return z+""; 31 else return biaodashi(z,m); 32 33 } 34 public static String biaodashi(int a,int b) {//判断假分数,并化假分数为带分数 35 if(a>=b) { 36 int c; 37 c=a/b; 38 int d; 39 d=a%b; 40 {if(d==0) {return c+"";} 41 return c+"'"+d+"/"+b;} 42 }return a+"/"+b; 43 } 44 45 public static void main(String[] args){ 46 Scanner sc= new Scanner(System.in); 47 System.out.println("请输入产生几以内的数字:"); 48 range=sc.nextInt(); 49 System.out.println("请输入产生多少个运算表达式:"); 50 int num=sc.nextInt(); 51 int rightcount[]=new int[num+2]; 52 int wrongcount[]=new int[num+2]; 53 int right1=0; 54 int wrong1=0; 55 String[] results=new String[num];int i; 56 for( i=0;i<num;i++){ 57 58 String expArr[]=new String[2];//定义生成的题目 59 int a= (int) (random.nextInt(range));//分子 60 int b= (int) (random.nextInt(range));//分母 61 int c= (int) (random.nextInt(range));//另一个分子 62 int d= (int) (random.nextInt(range));//另一个分母 63 int fuhao;//运算符 64 fuhao= (int) (random.nextInt(4)); 65 if(b!=0&&d!=0) {//分母均不为0时生成带有分数的计算题,同时计算结果 66 if(fuhao==0) { 67 int fenzi=a*d+b*c; 68 int fenmu=b*d; 69 expArr[0]=biaodashi(a,b)+'+'+biaodashi(c,d)+'='; 70 System.out.println(expArr[0]); 71 results[i]=reductionofFraction(fenzi, fenmu); 72 73 } 74 if(fuhao==1&&a*d-b*c>=0) { 75 int fenzi=a*d-b*c; 76 int fenmu=b*d; 77 expArr[0]=biaodashi(a,b)+'-'+biaodashi(c,d)+'='; 78 System.out.println(expArr[0]); 79 results[i]=reductionofFraction(fenzi, fenmu); 80 81 } 82 if(fuhao==1&&a*d-b*c<0) { 83 int fenzi=b*c-a*d; 84 int fenmu=b*d; 85 expArr[0]=biaodashi(a,b)+'-'+biaodashi(c,d)+'='; 86 System.out.println(expArr[0]); 87 results[i]=reductionofFraction(fenzi, fenmu); 88 89 } 90 if(fuhao==2) { 91 int fenzi=a*c; 92 int fenmu=b*d; 93 expArr[0]=biaodashi(a,b)+'×'+biaodashi(c,d)+'='; 94 System.out.println(expArr[0]); 95 results[i]=reductionofFraction(fenzi, fenmu); 96 97 } 98 if(fuhao==3&&c!=0) { 99 int fenzi=a*d; 100 int fenmu=b*c; 101 expArr[0]=biaodashi(a,b)+'÷'+biaodashi(c,d)+'='; 102 System.out.println(expArr[0]); 103 results[i]=reductionofFraction(fenzi, fenmu); 104 105 } 106 if(fuhao==3&&c==0) { 107 break; 108 /*c=1; 109 int fenzi=a*d; 110 int fenmu=b*c; 111 expArr[0]=biaodashi(a,b)+'÷'+biaodashi(c,d)+'='; 112 System.out.println(expArr[0]); 113 results[i]=reductionofFraction(fenzi, fenmu);*/ 114 115 } 116 117 } 118 else {//分母至少一个为0时生成只含有整式的运算式,同时计算结果 119 b=1; d=1; 120 if(fuhao==0) { 121 int fenzi=a*d+b*c; 122 int fenmu=b*d; 123 expArr[0]=a+"+"+c+"="; 124 System.out.println(expArr[0]); 125 results[i]=reductionofFraction(fenzi, fenmu); 126 127 } 128 if(fuhao==1&&a*d-b*c>=0) { 129 int fenzi=a*d-b*c; 130 int fenmu=b*d; 131 expArr[0]=a+"-"+c+"="; 132 System.out.println(expArr[0]); 133 results[i]=reductionofFraction(fenzi, fenmu); 134 135 } 136 if(fuhao==1&&a*d-b*c<0) { 137 int fenzi=b*c-a*d; 138 int fenmu=b*d; 139 expArr[0]=c+"-"+a+"="; 140 System.out.println(expArr[0]); 141 results[i]=reductionofFraction(fenzi, fenmu); 142 143 } 144 if(fuhao==2) { 145 int fenzi=a*c; 146 int fenmu=b*d; 147 expArr[0]=c+"×"+a+"="; 148 System.out.println(expArr[0]); 149 results[i]=reductionofFraction(fenzi, fenmu); 150 151 } 152 if(fuhao==3&&c!=0) { 153 int fenzi=a*d; 154 int fenmu=b*c; 155 expArr[0]=a+"÷"+c+"="; 156 System.out.println(expArr[0]); 157 results[i]=reductionofFraction(fenzi, fenmu); 158 159 } 160 if(fuhao==3&&c==0) { 161 break; 162 /*c=1; 163 int fenzi=a*d; 164 int fenmu=b*c; 165 expArr[0]=a+"÷"+c+"="; 166 System.out.println(expArr[0]); 167 results[i]=reductionofFraction(fenzi, fenmu);*/ 168 169 } 170 171 } 172 FileWriter fw = null; 173 try { 174 175 File f=new File("Exersies.txt");//题目写入 176 fw = new FileWriter(f, true); 177 } catch (IOException e) { 178 e.printStackTrace(); 179 }if(expArr[0]!=null) { 180 PrintWriter pw = new PrintWriter(fw); 181 pw.println(i+1+"."+expArr[0]); 182 pw.flush(); 183 try { 184 fw.flush(); 185 pw.close(); 186 fw.close(); 187 } catch (IOException e) { 188 e.printStackTrace(); 189 }}FileWriter fn = null; 190 try { 191 192 File f=new File("Answer.txt");//答案写入 193 fn = new FileWriter(f, true); 194 } catch (IOException e) { 195 e.printStackTrace(); 196 }if(expArr[0]!=null) { 197 PrintWriter pn = new PrintWriter(fn); 198 pn.println(i+1+"."+results[i]); 199 pn.flush(); 200 try { 201 fn.flush(); 202 pn.close(); 203 fn.close(); 204 } catch (IOException e) { 205 e.printStackTrace(); 206 }} 207 } 208 System.out.println("输入ok提交!"); 209 Scanner sc1=new Scanner(System.in); 210 String submit=sc1.nextLine(); 211 if(submit.equals("ok")){ 212 String array[]=new String[num]; 213 try 214 { int k=0; 215 216 FileReader fr = new FileReader("H://eclipse2//eclipse3//sizeyusuan//Your_answers.txt"); 217 BufferedReader br = new BufferedReader(fr); 218 String s ; 219 while((s = br.readLine())!=null) {//读取小学生的答案 220 array[k]=s; k++; 221 }br.close(); 222 fr.close(); 223 }catch(IOException e){ 224 System.out.println("指定文件不存在"); 225 } 226 for(int j=0;j<num;j++){ 227 if(array[j].equals(results[j])) {//验证答案,统计正确和错误的个数 228 229 rightcount[j]=j+1; 230 right1++; 231 } 232 else { 233 234 wrongcount[j]=j+1; 235 wrong1++; 236 } 237 } 238 FileWriter fg = null; 239 try { 240 //反馈正确与错误题目的信息 241 File f=new File("Grade.txt"); 242 fg = new FileWriter(f, true); 243 } catch (IOException e) { 244 e.printStackTrace(); 245 } 246 PrintWriter pg = new PrintWriter(fg); 247 pg.println(" "); 248 pg.print("Correct:"+right1+"("); 249 for (int j = 0; j <= num; j++) { 250 if (rightcount[j] != 0) { 251 pg.print(rightcount[j] + ","); 252 } 253 } 254 pg.println(")"); 255 pg.print("Wrong:"+wrong1+"("); 256 for (int j = 0; j <= num; j++) { 257 if (wrongcount[j] != 0) { 258 pg.print(wrongcount[j] + ","); 259 } 260 } 261 pg.print(")"); 262 pg.flush(); 263 try { 264 fg.flush(); 265 pg.close(); 266 fg.close(); 267 } catch (IOException e) { 268 e.printStackTrace(); 269 }} 270 } 271 }
2)测试用例设计 (结合单元测试的内容和模块功能设计测试用例)
新建一个名为 JUnit_Test 的项目,在其中编写一个 xiaoxuesheng 类。
开发一个自动生成小学四则运算题目的命令行 “软件”。实现 输入你要出题的个数,随机产生四则运算,然后用户回答,并且进行打分。
规则:用随机数实现100以内的加、减、乘、除运算,其中和与积不能超过100,差不为负(即须大减小),商不为小数或分数(即必须整除)。
要求总计输出10个运算式,每输出一个运算式,等待输入结果,然后进行对错判断并输出。最后输出统计答对的题数与分然后对这些功能进行单元测试。
3)选择的测试框架介绍、安装过程
将 JUnit4 单元测试包引入这个项目,在该项目上点击右键找属性,在弹出的属性窗口中,首先在左边选择“Java Build Path”,然后到右上选择“Libraries” 标签,之后在 最右边点击“Add Library…按钮,然后在新弹出的对话框中选择 JUnit4 并点击确定,如上图所示,JUnit4 软件包就被包含进我们这个项目了。
生成 JUnit 测试框架:在 Eclipse 的 Package Explorer 中用右键点击该类弹出菜单,选择“JUnit 测试用例”。在弹出的对话框中,进行相应的选择,如下图。
4 )测试代码
点击“下一步”后,系统会自动列出你这个类中包含的方法,选择你要进行测试的方法。此例中,我们仅对下图所勾选的选项进行测试。
之 后 系 统 会 自 动 生 成 一 个 新 类CalculatorTest,里面包含一些空的测试用例。
5)测试结果与分析
每一个测试方法上使用@Test进行修饰; 每一个测试方法必须使用public void 进行修饰;每一个测试方法不能携带参数
测试代码和源代码在两个不同的项目路径下;测试类的包应该和被测试类保持一致;测试单元中的每个方法必须可以独立测试。
运行测试代码:按照上述代码修改完毕后,我们在 CalculatorTest 类上点右键,选择“Run As ——>JUnit Test”来运行我们的测试。
具体的测试结果在进度条上面有表示“共进行了 3个测试,其中3个测试失败”。
3、push测试报告和测试代码到各自的github仓库
出现这个问题的最主要原因在于本地仓库和远程仓库实际上是独立的两个仓库 ,这就相当于你想直接拿一个不相干的仓库去覆盖另一个远程库, 肯定不会同意
这时, 只要,使用这个git pull --rebase origin master。此时再使用git push origin master就可以成功将文件 push 到你的远程仓库了。
思考题:
比较以下二个工匠的做法,你认为哪种好?结合编码和单元测试,谈谈你的认识。
我觉得这两种做法都有可取之处,工匠一的做法相当于是每编写一行代码就进行测试,在后面不会因为总的测试出现大量返工的情况,
但是会浪费很多时间。工匠二的做法固然节省时间,但如果出现大量错误改起来很费事。但我觉得孰能生巧,长时间编程错误率应该
不高,采取类似工匠二的做法很好。
实验小结
此次实验对我来说是针对本学期实验的总结,通过这次实验我对 git 实验和结对编程实验进行了一次回顾,更加熟练的掌握了实验方法,
对本地仓库及远程仓库之间的操作熟记于心。同时掌握了新的一种测试代码的工具,eclipse 中的 junit 插件真的很好用。