JUnit 4的參數化測試

最近在研究TestN與JUnit 4的優劣勢。在測試JUnit 4的@Parameters的時候,遇到initializationError的錯誤。所以,想徹底研究了一下這個問題出現的原因,並找出解決方法。

問題描述:

之前使用JUnit的時候,可以直接以JUnit test形式運行test類中某個用@Test註解的函數。但是如果test類中使用了@RunWith(Parameterized.class)註解,這種運行方法就會出現initializationError的錯誤。


被測試的類Math:

package com.ibm.junit.parameter;

/**
 * @author [email protected]
 *
 */
public class Math {

    public static int divide(int x,int y) {   
        return x/y;   
    }   
  
    public static int multiple(int x,int y) {   
        return x*y;   
    } 
}

測試的類MathTest:

package com.ibm.junit.parameter;

import static org.junit.Assert.assertEquals;

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

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
 * @author [email protected]
 *
 */

@RunWith(Parameterized.class)
public class MathTest {
    
    int faciend;
    int multiplicator;
    int result;

    @Parameters
    public static Collection multipleValues() {
        System.out.println("Initialize Data!");
     return Arrays.asList(new Object[][] {
        {2, 3, 6 },
        {3, 4, 12 },
        {4, 5, 20 }
     });
    }
    
    public MathTest(int faciend, int multiplicator, int result) {
        System.out.println("Constructor Method with no Parameters!");
        
        this.faciend = faciend;
        this.multiplicator = multiplicator;
        this.result = result;
    }
    
    /*public MathTest() {
        System.out.println("Constructor Method with no Parameters!");
    }*/

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
        System.out.println("Before Class!");
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
        System.out.println("After Class!");
    }

    @Test(expected=ArithmeticException.class)
    public void testDivide() {
        System.out.println("Test Divide");
        
        assertEquals(3,Math.divide(9,3));
        assertEquals(3,Math.divide(10,3));
        Math.divide(10,0);//除數不能爲0,會拋出異常
    }

    @Test
    public void testMultiple() {
        System.out.println("Test Multiple");
        
        assertEquals(result,Math.multiple(faciend,multiplicator));
    }
}


爲了分析問題,做了如下對比試驗:

1. 直接以JUnit test形式運行MathTest類

    如果運行整個MathTest類,測試通過,輸出如下:

Initialize Data!
Before Class!
Constructor Method with no Parameters!
Test Divide
Constructor Method with no Parameters!
Test Multiple
Constructor Method with no Parameters!
Test Divide
Constructor Method with no Parameters!
Test Multiple
Constructor Method with no Parameters!
Test Divide
Constructor Method with no Parameters!
Test Multiple
After Class!

    如果運行MathTest類中的testMultiple()方法,測試通不過,提示initializationError的錯誤。

2. 註釋掉MathTest類前面的@RunWith(Parameterized.class),提示java.lang.Exception: Test class should have exactly one public zero-argument constructor。後面會詳細分析註釋@RunWith(Parameterized.class)前後的區別。

3. 根據2中提示的錯誤,註釋有參構造函數,提供無參構造函數。不管是對整個MathTest類進行JUnit測試,還是對testMultiple()方法進行JUnit測試,都會通過。

4. 加上MathTest類前面的@RunWith(Parameterized.class),仍然提供無參構造函數,對MathTest類和方法的測試,都通不過,提示java.lang.IllegalArgumentException: 參數數目錯誤。
 

通過上面的對比試驗,下面結合JUnit參數測試的原理,來分析一下原因。

對於JUnit參數化測試,需要在測試類前加上@RunWith(Parameterized.class)。@RunWith用來指定該類使用參數化運行器運行,而不是使用默認情況下的JUnit內建的運行器運行。沒有@RunWith註解,就是使用JUnit內建的運行器運行,它需要無參構造函數,可以不自己提供而使用默認無參構造函數。試驗3說明了這個問題。雖然測試通過,但是由於沒有對參數賦值,參數都是使用的默認值,所以是無效的測試。

使用@RunWith註解,就必須提供有參構造函數。試驗4說明了這個問題。並且,每個測試函數運行前,都會調用有參構造函數初始化所有測試數據和驗證數據。試驗1的輸出結果說明這個。

同時,使用@RunWith註解之後,就不能單獨對測試類中單個測試函數進行測試。因爲單獨運行單個測試函數,不會在創建測試類前執行@Parameters註解的函數,不能爲參數化測試提供參數,所以會提示initializationError的錯誤。如果對測試類進行測試,就會在創建測試類前準備好測試數據,然後在執行每個測試函數前通過構造函數爲測試函數要用到的測試變量賦值。試驗1的輸出結果說明這個。


 

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章