`
longgangbai
  • 浏览: 7252400 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Junit4参数化测试

阅读更多

 

 


   现有这样一个接口,需要对其进行单元测试,代码如下:

publicclassJDemo{ 
/*
* 执行加法运算 
*/
publicint add(inta,int b){ 
returna+b; 
}

对该接口进行测试时,如果按照以前的测试方法,会编写类似如下的测试代码:

publicclass JDemoTest3 {

//测试0 0的情况 
@Test publicvoid add1(){ 
JDemo demo = newJDemo(); 
assertEquals(0, demo.add(0, 0)); 
} 

//测试正数、负数的情况 
@Test publicvoid add2(){ 
JDemo demo = newJDemo(); 
assertEquals(0, demo.add(1, -1)); 
} 

//测试正数、正数的情况 
@Test publicvoid add3(){ 
JDemo demo = newJDemo(); 
assertEquals(2, demo.add(1, 1)); 
} 
}

上面的测试方法存在严重的代码冗余并且不易维护,尤其当测试用例比较多时更加明显,现在我们基于Junit4的参数化来实现同样的功能,代码如下:

//声明所使用的运行器,如果未声明,则使用默认运行器。 
@RunWith(Parameterized.class) 
publicclassJDemoTest2 {

privateintresult; 
privateintadddata_a; 
privateintadddata_b; 

//参数化必须的构造方法,其中参数的顺序对应参数集中参数的顺序。 
public JDemoTest2(intresult,intadddata_a,intadddata_b){ 

this.adddata_a = adddata_a; 
this.adddata_b = adddata_b; 
this.result = result;
} 

@Test 
publicvoid add(){ 
JDemo demo = newJDemo(); 
assertEquals(result, demo.add(adddata_a, adddata_b)); 
} 

@SuppressWarnings("unchecked") 
@Parameters 
publicstatic Collection getParameters(){ 
returnArrays.asList(new Object[][]{ 
{0,0,0}, 
{0,1,-1}, 
{2,1,1} 
}); 
} 
}

使用Junit4参数化测试需要遵循其相应的规范,大致如下:
1. 为准备使用参数化测试的测试类指定特殊的运行器org.junit.runners.Parameterized。
2. 为测试类声明几个变量,分别用于存放期望值和测试所用数据。
3. 为测试类声明一个使用注解org.junit.runners.Parameterized.Parameters修饰的,返回值为java.util.Collection的公共静态方法,并在此方法中初始化所有需要测试的参数对。
4. 为测试类声明一个带有参数的公共构造函数,并在其中为步骤2中声明的几个变量赋值。
5. 编写测试方法,使用定义的变量作为参数进行测试。
关于Junit4参数化测试方法基本流程讲解完了,在实际工作中可根据需要加以应用

 

 

Junit与TestNG参数化测试比较

在TestNG中,直接使用@DataProvider进行参数化测试:

Java代码   收藏代码
  1. import org.testng.annotations.DataProvider;  
  2. import org.testng.annotations.Test;  
  3. import static org.testng.Assert.*;  
  4.   
  5. public class Addition {  
  6.     public int add(int a, int b) {  
  7.         return a+ b;  
  8.     }  
  9.       
  10.     @DataProvider(name = "addition")  
  11.     public Object[][] createData(){  
  12.         return new Object[][] {{1,2,3},{0,0,1},{-1,1,0},{-1,-2,-3}};  
  13.     }  
  14.       
  15.     @Test(dataProvider = "addition")  
  16.     public void addtionTest(int a1, int a2, int result){  
  17.         Addition ad = new Addition();  
  18.         assertEquals(ad.add(a1, a2), result);  
  19.     }  
  20.   
  21. }  

 而在Junit中一定要新建一个类,在构造函数中初始化数据:

Java代码   收藏代码
  1. import static org.junit.Assert.*;  
  2.   
  3. import java.util.Arrays;  
  4. import java.util.Collection;  
  5.   
  6. import org.junit.Test;  
  7. import org.junit.runner.RunWith;  
  8. import org.junit.runners.Parameterized;  
  9. import org.junit.runners.Parameterized.Parameters;  
  10.   
  11.   
  12. @RunWith(Parameterized.class)  
  13. public class AdditionTest {  
  14.     private int d1, d2;  
  15.     private int result;  
  16.     public AdditionTest(int d1, int d2, int result) {  
  17.         super();  
  18.         this.d1 = d1;  
  19.         this.d2 = d2;  
  20.         this.result = result;  
  21.     }  
  22.       
  23.     @Parameters  
  24.     @SuppressWarnings("unchecked")  
  25.     public static Collection getParamters(){  
  26.         Object [][] object = {{1,2,3},{0,0,0},{-1,1,0},{-1,-2,-3}};    
  27.         return Arrays.asList(object);        
  28.     }  
  29.       
  30.     @Test  
  31.     public void testAddition(){  
  32.         Addition ad = new Addition();  
  33.         assertEquals(this.result, ad.add(this.d1, this.d2));  
  34.     }  
  35.       
  36. }  

 结论:相较之下,用TestNG去实现可以让代码更加简单一些

 

 

ParallelComputer: 并行测试
当需要同时测试testcase的时候,你不需要为自己写thread来做这个事情。JUnit4已经有了这个特性,而且还提供多种同步选择。例如:


/**
 * @author longgangbai
 */ 
public class ParallelComputerTest { 
    
   @Test 
    public void test() {     
      Class[] cls={ParallelTest1.class,ParallelTest2.class }; 
       
      //Parallel among classes 
      JUnitCore.runClasses(ParallelComputer.classes(), cls); 
       
      //Parallel among methods in a class 
      JUnitCore.runClasses(ParallelComputer.methods(), cls); 
       
      //Parallel all methods in all classes 
      JUnitCore.runClasses(new ParallelComputer(true, true), cls);    
    } 
   public static class ParallelTest1{ 
      @Test public void a(){} 
      @Test public void b(){} 
   } 
   public static class ParallelTest2{ 
      @Test public void a(){} 
      @Test public void b(){} 
   } 

你有3种同步方式:

1: ParallelComputer.classes():所有测试类同时开始执行,但是每个类里面的方法还是顺序执行。在例子里面ParallelTest1 和ParallelTest2 同时开始,但是各自的a(),b() 还是顺序执行。

2: ParallelComputer.methods():测试类顺序执行,但是每个类里面的方法是同时开始执行。在例子里面ParallelTest1 的a() 和b() 同时开始,等结束之后再开始ParallelTest2 。

3: new ParallelComputer(true, true):所有测试类里面方法同时开始执行。在例子里面4个方法同时开始执行。

很有意思吧。

 

Category: 分类测试
当你有很多testcase,但是你不想每次都执行一遍的时候。你可以把testcase分成若干类,然后就可以分类有选择的来执行这些testcase。

例子:譬如你有2类testcase,一类是重要的用Important.class表示,还有一类不那么重要的用Secondary.class表示。


/**
 * @author longgangbai
 */ 
interface Important{}; 
interface Secondary{}; 
@RunWith(Categories.class) 
@IncludeCategory(Important.class) 
@ExcludeCategory(Secondary.class) 
@SuiteClasses( { CategoryTest.Alpha.class,  
                 CategoryTest.Beta.class }) 
public class CategoryTest { 
    
   @Category(Important.class) 
   public static class Alpha{//Alpha is Important except b 
      @Test  
      public void a(){} 
       
      @Test 
      @Category(Secondary.class) 
      public void b(){} 
   } 
    
   public static class Beta{ 
      @Test  
      @Category(Important.class) 
      public void a(){}//a is Important 
   } 

当你执行后会发现只有Alpha.a() 和Beta.a() 执行到,Alpha.b() 被@ExcludeCategory 掉了。

 

MaxCore: 失败优先
  当需要反复测试大量testcase的时候,你往往比较关注那些前一次失败的case。这个时候你就可以利用MaxCore特性在每次执行testcase的时候优先执行那些上次失败的case。

例如:


/**
 * @author longgangbai
 */ 
public class MaxCoreTest { 
    
   private MaxCore fMax; 
    
   @Before 
   public void createMax() { 
      File fMaxFile= new File("MaxCore.ser"); 
      fMax= MaxCore.storedLocally(fMaxFile); 
   } 
    
   @Test  
   public void test(){ 
      Request request= Request.aClass(Delta.class); 
      fMax.run(request); 
      fMax.run(request);//b->c->a 
   } 
    
   public static class Delta{ 
      @Test public void a(){} 
      @Test public void b(){ 
         Assert.fail(); 
      } 
      @Test public void c(){} 
   } 

可以观察到第2次执行的时候Delta.b() 由于第1次的失败而提前到了最先执行。

 

 

DataPoint: 参数数据
当需要测试不同输入参数的时候是不是要写一大堆testcase?不需要,因为JUnit4提供了参数化测试数据的特性。例如你想要测试2个整型数据作为输入参数的时候:


/**
 * @author longgangbai
 */ 
@RunWith(Theories.class) 
public class DataPointTest { 
   @DataPoint 
   public static int ONE= 1; 
   @DataPoint 
   public static int TWO= 2; 
  
   /* You could also use @DataPoints instead of @DataPoint
   @DataPoints
   public static int[] points= { 1, 2 };*/ 
  
   @Theory 
   public void test(int first, int second) { 
   } 

通过观察test() 被执行了4次,每次不同的组合作为参数输入。而且如果参数数目过多,你可以通过@DataPoints 一下子把参数都设进去。用过@RunWith(Parameterized.class) 的朋友可以和DataPoint做一下比较。

TestedOn
这个功能也是参数化数据,只不过它是直接在参数上配置。例如:


@Theory 
public void test2(@TestedOn(ints={1,2})int first) { 
    System.out.println(first); 

结果打印出来"1 ,2" 。

 

 

PrintableResult: 打印结果
这个我认为倒是一个小功能,它只是把测试失败的结果以比较美观的格式打出来。例如:


Result result = JUnitCore.runClasses(SomeTest.class); 
System.out.println(new PrintableResult(result.getFailures())); 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics