实验五 单元测试

一、实验目的

1)掌握单元测试的方法

2) 学习XUnit测试原理及框架;

3)掌握使用测试框架进行单元测试的方法和过程。

二、实验内容与要求

1、了解单元测试的原理与框架

    

 1.1 单元测试原理

  单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如C语言中单元指一个函数,Java里单元指一个类,图形化的软件中可以指一个窗口或一个菜单等。总的来说,单元就是人为规定的最小的被测功能模块。单元测试是在软件开发过程中要进行的最低级别的测试活动,软件的独立单元将在与程序的其他部分相隔离的情况下进行测试。单元测试是由程序员自己来完成,最终受益的也是程序员自己。可以这么说,程序员有责任编写功能代码,同时也就有责任为自己的代码编写单元测试。执行单元测试,就是为了证明这段代码的行为和我们期望的一致。

单元测试的内容包括

  模块接口测试、局部数据结构测试、路径测试、错误处理测试、边界测试

(1)模块接口测试

模块接口测试是单元测试的基础。只有在数据能正确流入、流出模块的前提下,其他测试才有意义。模块接口测试也是集成测试的重点,这里进行的测试主要是为后面打好基础。测试接口正确与否应该考虑下列因素: 

    -输入的实际参数与形式参数的个数是否相同 

    -输入的实际参数与形式参数的属性是否匹配 

    -输入的实际参数与形式参数的量纲是否一致 

    -调用其他模块时所给实际参数的个数是否与被调模块的形参个数相同; 

    -调用其他模块时所给实际参数的属性是否与被调模块的形参属性匹配; 

    -调用其他模块时所给实际参数的量纲是否与被调模块的形参量纲一致; 

    -调用预定义函数时所用参数的个数、属性和次序是否正确; 

    -是否存在与当前入口点无关的参数引用; 

    -是否修改了只读型参数; 

    -对全程变量的定义各模块是否一致; 

    -是否把某些约束作为参数传递。

如果模块功能包括外部输入输出,还应该考虑下列因素: 

-文件属性是否正确; 

-OPEN/CLOSE语句是否正确; 

-格式说明与输入输出语句是否匹配; 

-缓冲区大小与记录长度是否匹配; 

-文件使用前是否已经打开; 

-是否处理了文件尾; 

-是否处理了输入/输出错误; 

-输出信息中是否有文字性错误。 

-局部数据结构测试; 

-边界条件测试; 

-模块中所有独立执行通路测试;

 

(2)局部数据结构测试

    检查局部数据结构是为了保证临时存储在模块内的数据在程序执行过程中完整、正确,局部功能是整个功能运行的基础。重点是一些函数是否正确执行,内部是否运行正确。局部数据结构往往是错误的根源,应仔细设计测试用例,力求发现下面几类错误: 

-不合适或不相容的类型说明; 

-变量无初值; 

-变量初始化或省缺值有错; 

-不正确的变量名(拼错或不正确地截断); 

-出现上溢、下溢和地址异常。

 

(3)边界条件测试

    边界条件测试是单元测试中最重要的一项任务。众所周知,软件经常在边界上失效,采用边界值分析技术,针对边界值及其左、右设计测试用例,很有可能发现新的错误。边界条件测试是一项基础测试,也是后面系统测试中的功能测试的重点,边界测试执行的较好,可以大大提高程序健壮性。

(4)独立路径测试

    在模块中应对每一条独立执行路径进行测试,单元测试的基本任务是保证模块中每条语句至少执行一次。测试目的主要是为了发现因错误计算、不正确的比较和不适当的控制流造成的错误。具体做法就是程序员逐条调试语句。常见的错误包括: 

-误解或用错了算符优先级; 

-混合类型运算; 

-变量初值错; 

-精度不够; 

-表达式符号错。

(5)错误处理测试

   检查模块的错误处理功能是否包含有错误或缺陷。例如,是否拒绝不合理的输入;出错的描述是否难以理解、是否对错误定位有误、是否出错原因报告有误、是否对错误条件的处理不正确;在对错误处理之前错误条件是否已经引起系统的干预等。

     通常单元测试在编码阶段进行。在源程序代码编制完成,经过评审和验证,确认没有语法错误之后,就开始进行单元测试的测试用例设计。利用设计文档,设计可以验证程序功能、找出程序错误的多个测试用例。对于每一组输入,应有预期的正确结果。

 

1.2 测试框架

 xUnit是各种代码驱动测试框架的统称,这些框架可以测试 软件的不同内容(单元),比如函数和类。xUnit框架的主要优点是,它提供了一个自动化测试的解决方案。可以避免多次编写重复的测试代码。

 

底层是xUnit的framwork,xUnit的类库,提供了对外的功能方法、工具类、api等

TestCase(具体的测试用例)去使用framwork

TestCase执行后会有TestResult

使用TestSuite控制TestCase的组合

TestRunner执行器,负责执行case

TestListener过程监听,监听case成功失败以及数据结果,输出到结果报告中

 

Unit测试框架包括四个要素:

      (1)测试目标(对象)

  一组认定被测对象或被测程序单元测试成功的预定条件或预期结果的设定。Fixture就是被测试的目标,可以是一个函数、一组对象或一个对象。  测试人员在测试前应了解被测试的对象的功能或行为。

    (2)测试集

测试集是一组测试用例,这些测试用例要求有相同的测试Fixture,以保证这些测试不会出现管理上的混乱。

    (3)测试执行

单个单元测试的执行可以按下面的方式进行:

第一步 编写 setUp() 函数,目的是:建立针对被测试单元的独立测试环境;举个例子,这可能包含创建临时或代理的数据库、目录,再或者启动一个服务器进程。

第二步 编写所有测试用例的测试体或者测试程序;

第三步 编写tearDown()函数,目的是:无论测试成功还是失败,都将环境进行清理,以免影响后续的测试;

    (4)断言  

    断言实际上就是验证被测程序在测试中的行为或状态的一个函数或者宏。断言的失败会引发异常,终止测试的执行。

 

 

1.3   面向特定语言的

基于xUnit框架的自动化测试框架

    Junit  : 主要测试用Java语言编写的代码

    CPPunit:主要测试用C++语言编写的代码

   unittest , PyUnit:主要测试用python语言编写的代码

   MiniUnit:   主要用于测试C语言编写的代码

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)测试用例设计 (结合单元测试的内容和模块功能设计测试用例)

新建一个名为sunxiya 的项目,在其中编写一个 xiaoxuesheng 类。开发一个自动生成小学四则运算题目的命令行 “软件”。实现 输入你要出题的个数,随机产生四则运算,然后用户回答,并且进行打分。规则:用随机数实现100以内的加、减、乘、除运算,其中和与积不能超过100,差不为负(即须大减小),商不为小数或分数(即必须整除)。要求总计输出10个运算式,每输出一个运算式,等待输入结果,然后进行对错判断并输出。最后输出统计答对的题数与分然后对这些功能进行单元测试。

 

 3)安装Junit

将 JUnit4单元测试包引入这个项目,在属性窗口添加Junit,选择Junit4

 

 

 

4)创建测试用例

生成JUnit测试框架,在Eclipse的Package Explorer中用右键点击该类弹出菜单,选择"JUnit测试用例"。在弹出的对话框中,进行相应的选择

 

 

 

 

 5)测试代码

点击“下一步”后,系统会自动列出你这个类中包含的方法,选择你要进行测试的方法。此例中,我们仅对下图所勾选的选项进行测试。

之 后 系 统 会 自 动 生 成 一 个 新 类CalculatorTest,里面包含一些空的测试用例。

 

 

 6)测试结果

 

 共进行了 3个测试,其中3个测试失败

 

 

 3、push测试报告和测试代码到自己的github仓库

思考题:

比较以下二个工匠的做法,你认为哪种好?结合编码和单元测试,谈谈你的认识。

 以单元测试的想法来看,工匠二的做法更好,相当于是在编写程序时设计多个函数,对每个函数进行测试更方便找出代码的不足之处,如果只写一个函数不方便测试。不容易找出测试的切入点。其实每个工匠的做法都有各自的优点。

实验小结

此次实验用的编译器在进行各种操作时比较方便。本次实验找出来的bug虽然不会影响程序的运行,但是会影响测试的速度,存在着潜在隐患,对测试人员和开发人员产生一定的影响。我们要对代码进行重构和优化,使其更加规范。

posted @ 2020-06-01 17:15  3170701112孙习雅  阅读(168)  评论(0编辑  收藏  举报