Chinaunix首页 | 论坛 | 博客
  • 博客访问: 93554
  • 博文数量: 16
  • 博客积分: 1410
  • 博客等级: 上尉
  • 技术积分: 175
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-04 15:33
文章分类

全部博文(16)

文章存档

2009年(5)

2008年(11)

我的朋友

分类: Java

2008-06-16 15:39:26

JUnit 4 放弃了过去严格的命名规范和继承层次,转而推崇 Java™ 5 注释的灵活性。本篇介绍了如何充分利用由注释实现的新功能,包括异常测试、计时测试、忽略测试、参数测试、测试套件、Fixture。
 
一、"@Test"有两个非常有用的参数
A.        异常检测
"@Test""expected"参数用来说明希望抛出的异常,如果运行时没有抛出这个异常,测试用例就被标识为失败。
    @Test(expected=ArithmeticException.class)
    publicvoid test2() {
       int z = x / 0;
       Assert.assertEquals(2, z);
    }
B.        超时测试
"@Test"有一个timeout的参数用来说明这个测试用例运行的时间最长应该为多少,如果时间超出,则标识为失败。
    @Test(timeout=500)    
    publicvoid test3(){
       for (int i=0;i<100;i++){
         try {
           Thread.sleep(10);
        } catch (InterruptedException e) {
           // TODO Auto-generated catch block
           e.printStackTrace();
        }
       }
    }
二、忽略测试
@Ignore的注释,它迫使该框架忽略掉一个特别的测试方法。也可以传入一条消息来向恰巧进行这项忽略测试的可信的开发人员传达您的决定。
    @Ignore("暂时忽略")
    @Test
    publicvoid test4(){
        Assert.assertEquals(2, 1);
    }
三、参数测试
偶尔,应用程序的业务逻辑要求您编写许多不定量的测试来保证其健壮。在 JUnit 之前的版本中,这种场景很不方便,主要是因为一个测试中方法的参数组各不相同,意味着要为每一个单独的组编写一个测试用例。
JUnit 4 引入了一项卓越的新功能,即能够创建由参数值供给的通用测试。结果是,您可以创建一个单个的测试用例并多次运行 —— 为您创建的每个参数运行一次。
在 JUnit 4 中创建参数测试只需要五个步骤:
  1. 创建一个不含参数的通用测试。
  2. 创建一个返回 Collection 类型的 static方法,并用 @Parameter 注释加以修饰。
  3. 为在步骤 1 中定义的通用方法所要求的参数类型创建类成员。
  4. 创建一个持有这些参数类型的构造函数,并把这些参数类型和步骤 3 中定义的类成员相应地联系起来。
  5. 通过 @RunWith 注释,指定测试用例和 Parameterized 类一起运行。
@RunWith(Parameterized.class)
publicclass TestWordDealUtilWithParam {
   private String expected;
  
   private String target;
 
   @Parameters
   publicstatic Collection words(){
         return Arrays.asList(new Object[][]{
          {"employee_info", "employeeInfo"},     //测试一般的处理情况
          {null, null},                  //测试 null 时的处理情况
          {"", ""},                     //测试空字符串时的处理情况
          {"employee_info", "EmployeeInfo"},     //测试当首字母大写时的情况
          {"employee_info_a", "employeeInfoA"}, //测试当尾字母为大写时的情况
          {"employee_a_info", "employeeAInfo"} //测试多个相连字母大写时的情况
         });
   }
 
  /**
  *参数化测试必须的构造函数
  *@paramexpected   期望的测试结果,对应参数集中的第一个参数
  *@paramtarget 测试数据,对应参数集中的第二个参数
  */
   public TestWordDealUtilWithParam(String expected , String target){
      this.expected = expected;
      this.target = target;
   }
 
  /**
  *实际需要测试的方法
  */
   @Test
   publicvoid wordFormat4DB(){
      assertEquals(expected, WordDealUtil.wordFormat4DB(target));
   }
再如:
JUnit4中参数化测试要点:

1. 测试类必须由Parameterized测试运行器修饰

2. 准备数据。数据的准备需要在一个方法中进行,该方法需要满足一定的要求:

1)该方法必须由Parameters注解修饰
2)该方法必须为public static的
3)该方法必须返回Collection类型
4)该方法的名字不做要求
5)该方法没有参数

如:
测试方法:
public int add(int a,int b){
  return a+b;
 }


测试代码:
package org.test;

import java.util.Arrays;
import java.util.Collection;

import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
 * 参数化测试的类必须有Parameterized测试运行器修饰
 *
 */
@RunWith(Parameterized.class)
public class AddTest3 {

 private int input1;
 private int input2;
 private int expected;
 
 /**
  * 准备数据。数据的准备需要在一个方法中进行,该方法需要满足一定的要求:

   1)该方法必须由Parameters注解修饰
   2)该方法必须为public static的
   3)该方法必须返回Collection类型
   4)该方法的名字不做要求
   5)该方法没有参数
  * @return
  */
 @Parameters
 @SuppressWarnings("unchecked")
 public static Collection prepareData(){
  Object [][] object = {{-1,-2,-3},{0,2,2},{-1,1,0},{1,2,3}};
  return Arrays.asList(object);
 }
 
 public AddTest3(int input1,int input2,int expected){
  this.input1 = input1;
  this.input2 = input2;
  this.expected = expected;
 }
 @Test
 public void testAdd(){
  Add add = new Add();
  int result = add.add(input1, input2);
  Assert.assertEquals(expected,result);
 }
 
}
四、测试套件
测试运行器,JUnit 中所有的测试方法都是由它负责执行的。JUnit 为单元测试提供了默认的测试运行器,但 JUnit 并没有限制您必须使用默认的运行器。相反,您不仅可以定制自己的运行器(所有的运行器都继承自 org.junit.runner.Runner),而且还可以为每一个测试类指定使用某个具体的运行器。指定方法也很简单,使用注解 org.junit.runner.RunWith 在测试类上显式的声明要使用的运行器即可。
在实际项目中,随着项目进度的开展,单元测试类会越来越多,可是直到现在我们还只会一个一个的单独运行测试类,这在实际项目实践中肯定是不可行的。为了解决这个问题,JUnit 提供了一种批量运行测试类的方法,叫做测试套件。这样,每次需要验证系统功能正确性时,只执行一个或几个测试套件便可以了。测试套件的写法非常简单,您只需要遵循以下规则:
  1. 创建一个空类作为测试套件的入口。
  2. 使用注解 org.junit.runner.RunWith 和 org.junit.runners.Suite.SuiteClasses 修饰这个空类。
  3. 将 org.junit.runners.Suite 作为参数传入注解 RunWith,以提示 JUnit 为此类使用套件运行器执行。
  4. 将需要放入此测试套件的测试类组成数组作为注解 SuiteClasses 的参数。
  5. 保证这个空类使用 public 修饰,而且存在公开的不带有任何参数的构造函数。
@RunWith(Suite.class)
@SuiteClasses({TestOld.class,TestNew.class})
publicclass JUnit4Suite {
 
}                          
五、Fixture的强大功能
何谓 Fixture?它是指在执行一个或者多个测试方法时需要的一系列公共资源或者数据,例如测试环境,测试数据等等。在编写单元测试的过程中,您会发现在大部分的测试方法在进行真正的测试之前都需要做大量的铺垫——为设计准备 Fixture 而忙碌。这些铺垫过程占据的代码往往比真正测试的代码多得多,而且这个比率随着测试的复杂程度的增加而递增。当多个测试方法都需要做同样的铺垫时,重复代码的“坏味道”便在测试代码中弥漫开来。这股“坏味道”会弄脏您的代码,还会因为疏忽造成错误,应该使用一些手段来根除它。
"Before"修饰的函数将会在每个测试运行前运行,"After"修饰的函数将在每个测试用例运行后运行。JUnit4.0支持任意数量的 "Before"和"After" Annotation,并且支持继承。"Before"修饰函数的执行顺序为父类的在前,继承类在后,"After"则相反,继承类在前,父类在后。
公共Fixture 的设置也很简单,您只需要:
  1. 使用注解 org,junit.Before 修饰用于初始化 Fixture 的方法。
  2. 使用注解 org.junit.After 修饰用于注销 Fixture 的方法。
  3. 保证这两种方法都使用 public void 修饰,而且不能带有任何参数。
 
"BeforeClass"修饰的函数将会在所有的测试用例运行前运行一次(只运行一次), "AfterClass"则会在所有的测试用例运行后运行一次(只运行一次)。
类级别的 Fixture 设置方法,编写规范如下:
  1. 使用注解 org,junit.BeforeClass 修饰用于初始化 Fixture 的方法。
  2. 使用注解 org.junit.AfterClass 修饰用于注销 Fixture 的方法。
  3. 保证这两种方法都使用 public static void 修饰,而且不能带有任何参数。
    @Before
    publicvoid beginM(){
       System.out.println("method Before...");
    }
    
    @After
    publicvoid afterM(){
       System.out.println("method after...");
    }
    
    @BeforeClass
    staticpublicvoid beginC(){
       System.out.println("Class Before...");
    }
    
    @AfterClass
    staticpublicvoid afterC(){
       System.out.println("Class after...");
    }
六、数组内容的新断言
添加了一个用于比较数组内容的新断言方法。这并不是什么重大举动,但它的确意味着您将不必再在数组内容间迭代,也不必再断言每个独立条目了。
@Test
public void verifyArrayContents() throws Exception{
 String[] actual = new String[] {"JUnit 3.8.x", "JUnit 4", "TestNG"};
 String[] var = new String[] {"JUnit 3.8.x", "JUnit 4.1", "TestNG 5.5"};
 assertEquals("the two arrays should not be equal", actual, var);           
}
阅读(2595) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~