Java單元測試之JUnit篇

單元測試是編寫測試代碼,應該準確、快速地保證程序基本模塊的正確性。
好的單元測試的標準
JUnit是Java單元測試框架,已經在Eclipse中默認安裝。html

JUnit4

JUnit4經過註解的方式來識別測試方法。目前支持的主要註解有:框架

  • @BeforeClass 全局只會執行一次,並且是第一個運行
  • @Before 在測試方法運行以前運行
  • @Test 測試方法
  • @After 在測試方法運行以後容許
  • @AfterClass 全局只會執行一次,並且是最後一個運行
  • @Ignore 忽略此方法

下面基於Eclipse介紹JUnit的基本應用

基本測試eclipse

  1. 新建一個項目叫JUnitTest,咱們編寫一個Calculator類,這是一個可以簡單實現加減乘除、平方、開方的計算器類,而後對這些功能進行單元測試。
public class Calculator {
    private static int result; // 靜態變量,用於存儲運行結果
    public void add(int n) {
        result = result + n;
    }
    public void substract(int n) {
        result = result - 1;  //Bug: 正確的應該是 result =result-n
    }
    public void multiply(int n) {
    }         // 此方法還沒有寫好
    public void divide(int n) {
        result = result / n;
    }
    public void square(int n) {
        result = n * n;
    }
    public void squareRoot(int n) {
        for (; ;) ;            //Bug : 死循環
    }
    public void clear() {     // 將結果清零
        result = 0;
    }
    public int getResult(){
        return result;
    }
}
  1. 將JUnit4單元測試包引入這個項目:在該項目上點右鍵,點「屬性」,如圖

    在彈出的屬性窗口中,首先在左邊選擇「Java Build Path」,而後到右上選擇「Libraries」標籤,以後在最右邊點擊「Add Library…」按鈕,以下圖所示



    而後在新彈出的對話框中選擇JUnit4並點擊肯定,如上圖所示,JUnit4軟件包就被包含進咱們這個項目了。
  2. 生成JUnit測試框架:在Eclipse的Package Explorer中用右鍵點擊該類彈出菜單,選擇「New JUnit Test Case」。以下圖所示:



    點擊「下一步」後,系統會自動列出你這個類中包含的方法,選擇你要進行測試的方法。此例中,咱們僅對「加、減、乘、除」四個方法進行測試。

    以後系統會自動生成一個新類CalculatorTest,裏面包含一些空的測試用例。你只須要將這些測試用例稍做修改便可使用。
    完整的CalculatorTest代碼以下:
public class CalculatorTest {   
    private static Calculator calculator = new Calculator();

    @Before
    public void setUp() throws Exception {
        calculator.clear();
    }

    @Test
    public void testAdd() {
        calculator.add(3);
        calculator.add(4);
        assertEquals(7, calculator.getResult());

    }

    @Test
    public void testSubstract() {
        calculator.add(8);
        calculator.substract(3);
        assertEquals(5, calculator.getResult());

    }

    @Ignore("Multiply() Not yet implemented")
    @Test
    public void testMultiply() {
        fail("Not yet implemented");
    }

    @Test
    public void testDivide() {
        calculator.add(8);
        calculator.divide(2);
        assertEquals(4, calculator.getResult());

    }

}
  1. 運行測試代碼:按照上述代碼修改完畢後,咱們在CalculatorTest類上點右鍵,選擇「Run As a JUnit Test」來運行咱們的測試,以下圖所示

    運行結果以下:

    進度條是紅顏色表示發現錯誤,具體的測試結果在進度條上面有表示「共進行了4個測試,其中1個測試被忽略,一個測試失敗」。
    限時測試
    對於那些邏輯很複雜,循環嵌套比較深的程序,頗有可能出現死循環,所以必定要採起一些預防措施。限時測試是一個很好的解決方案。咱們給這些測試函數設定一個執行時間,超過了這個時間,他們就會被系統強行終止,而且系統還會向你彙報該函數結束的緣由是由於超時,這樣你就能夠發現這些Bug了。要實現這一功能,只須要給@Test標註加一個參數便可,代碼以下:
@Test(timeout = 1000)
    public void squareRoot() {
        calculator.squareRoot(4);
        assertEquals(2, calculator.getResult());
    }

Timeout參數代表了你要設定的時間,單位爲毫秒,所以1000就表明1秒。ide


測試異常

JAVA中的異常處理也是一個重點,所以你常常會編寫一些須要拋出異常的函數。那麼,若是你以爲一個函數應該拋出異常,可是它沒拋出,這算不算Bug呢?這固然是Bug,並JUnit也考慮到了這一點,來幫助咱們找到這種Bug。例如,咱們寫的計算器類有除法功能,若是除數是一個0,那麼必然要拋出「除0異常」。所以,咱們頗有必要對這些進行測試。代碼以下:函數

@Test(expected = ArithmeticException.class)
  public void divideByZero(){
        calculator.divide(0);
   }

如上述代碼所示,咱們須要使用@Test標註的expected屬性,將咱們要檢驗的異常傳遞給他,這樣JUnit框架就能自動幫咱們檢測是否拋出了咱們指定的異常。
參數化測試
咱們可能遇到過這樣的函數,它的參數有許多特殊值,或者說他的參數分爲不少個區域。
例如,測試一下「計算一個數的平方」這個函數,暫且分三類:正數、0、負數。在編寫測試的時候,至少要寫3個測試,把這3種狀況都包含了,這確實是一件很麻煩的事情。測試代碼以下:單元測試

public class AdvancedTest { 
        private static Calculator calculator = new Calculator();
        @Before
        public void clearCalculator(){
            calculator.clear();
        }

        @Test
        public void square1() {
            calculator.square(2);
            assertEquals(4, calculator.getResult());
        }     

        @Test    
        public void square2(){
            calculator.square(0);
            assertEquals(0, calculator.getResult());
        }

        @Test    
        public void square3(){
            calculator.square(-3);
            assertEquals(9, calculator.getResult());
        }
     }

爲了簡化相似的測試,JUnit4提出了「參數化測試」的概念,只寫一個測試函數,把這若干種狀況做爲參數傳遞進去,一次性的完成測試。代碼以下:測試

@RunWith(Parameterized.class)
    public class SquareTest{
        private static Calculator calculator = new Calculator();
        private int param;
        private int result;     

    @Parameters    
    public static Collection data() {
        return Arrays.asList(new Object[][]{
               {2, 4},
               {0, 0},
               {-3, 9},
        });
    }

    //構造函數,對變量進行初始化
    public SquareTest(int param, int result){
        this.param = param;
            this.result = result;
    }

    @Test    
    public void square(){
        calculator.square(param);
        assertEquals(result, calculator.getResult());
    }
 }

執行了3次該測試類,依次採用了數據集合中的數據{處理值,預期處理結果},結果以下:

代碼分析以下:ui

  • 爲這種測試專門生成一個新的類,而不能與其餘測試共用同一個類,此例中咱們定義了一個SquareTest類。
  • 爲這個類指定一個Runner,而不能使用默認的Runner,@RunWith(Parameterized.class)這條語句就是爲這個類指定了一個ParameterizedRunner
  • 定義一個待測試的類,而且定義兩個變量,一個用於存放參數,一個用於存放期待的結果。
  • 定義測試數據的集合,也就是上述的data()方法,該方法能夠任意命名,可是必須使用@Parameters標註進行修飾。
  • 定義構造函數,其功能就是對先前定義的兩個參數進行初始化
相關文章
相關標籤/搜索