单元测试(Junit3.8)原则和测试用例

来源:互联网 发布:禅道数据库配置 linux 编辑:程序博客网 时间:2024/05/16 00:43
 

1、我们应该怎么做
编写代码之前,先编写单元测试,即测试先行。也就是所谓的测试驱动开发(TDD)
单元测试是代码的一部分,所有的代码必须有单元测试,并且测试通过。
在修改代码之前,先修改单元测试,并且测试通过。

当我们在对代码进行重构和进行设计优化时,如果我们对所有的类都编写了测试,
那么我们重构代码的时候很轻松的进行测试我们的修改是否正确。
当我们接到一个bug报告后,我们总是先修改测试代码,然后修改实现代码,使之测试成功。

2、为什么要编写单元测试
编写单元测试并不会增加了工作负担延缓项目进度
(1)、以一个web应用开发为例:业务代码编写完成->打包->发布到服务器->进行功能测试->发现问题->修改代码->再打包……如此循环。
任何一个web程序员对于这种开发情景都不会感到陌生。往往不断的打包,发布,功能测试的时间是代码编写的10倍以上。
通过集成系统来发现程序的bug,我们往往很难一下子准确的定位bug产生的地方。如果第一次没彻底修改这个bug或者修改这个bug
已经影响到其它的地方,这样部署上去肯定又有bug。又的业务代码编写完成->打包->发布到服务器->进行功能测试。
如果为每一个类都编写单元测试并让每一个方法测试通过,又会是怎么样的开发情景呢?
编写测试代码->编写业务代码->运行测试方法->修改代码让测试通过->所有的类都通过测试->打包->发布到服务器->进行功能测试->发现bug->修改测试代码->修改业务代码->测试通过->再打包…如此循环。
这样降低了打包->发布到服务器->进行功能测试的次数。

(2)  另外,如果没有单元测试,会经常出现一些低级的错误,如拼写错误,空指针异常等。
就因为一个小小的拼写错误而需要重新打包,发布一次。如果有单元测试,就可以避免这些低级的错误。
(3)在离bug产生越近,修正bug就越容易;在bug产生越远,修正bug的代价就越昂贵。
假设我们去集成一个星期(甚至更长时间)前编写的代码,当发现问题时,我们已经忘掉了很多重要的实现细节,
所以修改变得困难重重。

3、编写单元测试的基本原则
(1)学会使用断言:断言就是让我们为方法设置一个期望值。当方法执行结果与期望值不一致时,测试组件就会报告测试不通过。

(2)最大化测试覆盖率:我们除了测试一个正确的路径外,我们还需要测试方法的每一个分支逻辑。
需要编写尽可能多的测试程序逻辑的测试。写一个充分的测试。

(3)不要依赖于测试方法的执行顺序:使用Junit来进行单元测试,它不能保证测试方法按照我们的意图的顺序来执行。
当一个测试类有多个测试方法时,我们不能让一个测试方法必须在某一个测试之后执行才能成功。
Junit不能为我们做这样的保证,我们不能依赖于测试方法的执行顺序。

(4)针对接口测试:我们有“针对接口编程”的oo设计原则。同样对于测试,我们也需要针对接口测试。
也就是说在编写单元测试时,测试对象总是使用接口,而不是使用具体类。

4、编写单元测试的作用
单元测试能够提高程序员对程序的信心,保证程序的质量,加快软件开发速度,使程序易于维护。

5、编写测试用例
public int divide(int a, int b) throws Exception{
 if(0 == b){
  throw new Exception("除数不能为0");
 }
 
 return a / b;
}
(1)对方法有抛出异常的方法设计测试用例
如果被测试方法抛出异常。则需要设计两个测试用例
     1),设计正常的用例
 在测试用例中try catche 然后捕获后设置断言为Assert.fail();
 public void testDivide(){
  int result = 0;
  try{
   result = cal.divide(6, 2);
  }
  catch (Exception e){
   e.printStackTrace();
   Assert.fail("测试失败");
  }
  
  Assert.assertEquals(3, result);
 }
     2),设计抛出异常的用例
       public void testDivideDivideByZero(){
  Throwable tx = null;
  try{
   cal.divide(6, 0);
   Assert.fail("测试失败");
  }
  catch(Exception ex){
   tx = ex;
  }
  //判断是否抛了异常
  Assert.assertNotNull(tx);
  //判断异常类型是否一致
  Assert.assertEquals(Exception.class, tx.getClass());
  //判断异常信息是否一致
  Assert.assertEquals("除数不能为0", tx.getMessage());
 }
 
      3)、私有方法的测试,使用类的反射机制
 public void testAdd()
 {
  try{
   Calculator cal = new Calculator();

   Class<Calculator> clazz = Calculator.class;

   Method method = clazz.getDeclaredMethod("add", new Class[] {
     Integer.TYPE, Integer.TYPE });

   method.setAccessible(true);

   Object result = method.invoke(cal, new Object[] { 2, 3 });

   Assert.assertEquals(5, result);

  }
  catch (Exception ex){
   Assert.fail();
  }

 }