1. 程式人生 > >Java 單元測試利器之 Junit

Java 單元測試利器之 Junit

 前言:

          因為工作和學習的需要,在程式碼中查錯的時候,第一步就是想知道這個錯誤具體發生在一個位置,進行一個準確的定位。而這個定位的工作交給誰來做了呢?不難猜出也就是這篇部落格的主題---Junit。junit是一個開源的框架,也是java這一塊的測試工具之一。想了解詳細請上官網,下面用程式碼來跟大家解釋。

         準備要測試的方法,放進一個類中方便於測試。

複製程式碼
package com.junit3_8;

/**
 * junt3.8單元測試
 * 
 * @author CHH
 * @since 2013-01-19
 * 
 */
public class Calculator {

    
// public int add(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("加=="+sum); return a+b; } // public int subtract(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum
+=i; } System.out.println("減=="+sum); return a - b; } // public int multiply(int a, int b) { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("乘==="+sum); return a * b; }
// public int divide(int a, int b) throws Exception { int sum=0; for(int i=0;i<100;i++){ sum +=i; } System.out.println("除==="+sum); if (0 == b) { throw new Exception("除數不能為0"); } return a / b; } }
複製程式碼

        Junit3.8測試類

複製程式碼
package com.junit3_8;

import junit.framework.Assert;
import junit.framework.TestCase;
/**
 * 
 * @author CHH
 * @since 2013-01-19
 */
public class CalculatorTest extends TestCase {
    
    Calculator cal;
    
    //在“每個”測試方法執行之前被呼叫  
    public void setUp()  
    {  
        //這段程式碼在這寫比較方便,只寫一次就夠,  
        //不用在每個方法裡寫,因為這個方法每次都被呼叫,生成不同的物件,供測試方法使用  
        cal = new Calculator();  
    }
    
    //在“每個”測試方法執行之後被呼叫  
    public void tearDown()  
    {  
         
    }
    
    //測試方法:方法名要以test為開頭,無引數,無返回型別  
    public void testAdd()  
    {  
        //Calculator cal = new Calculator();  
        int result = cal.add(1, 2); 
        //第一個引數是預期的,第二個引數是真實的  
        
        Assert.assertEquals(3, result); 
        
        //Assert.fail();
          
    } 
    
    public void testSubtract()  
    {  
        //Calculator cal = new Calculator();  
        int result = cal.subtract(1, 2);  
        //第一個引數是預期的,第二個引數是真實的  
        Assert.assertEquals(-1, result);  
          
    }
    
    public void testMultiply()  
    {  
        //Calculator cal = new Calculator();  
        int result = cal.multiply(1, 2);  
        //第一個引數是預期的,第二個引數是真實的  
        Assert.assertEquals(2, result);  
          
    }
    
    public void testDivide()  
    {  
        int result = 0;  
        //Calculator cal = new Calculator();  
        try   
        {  
            result = cal.divide(4, 2);  
              
        }  
        catch(Exception e)  
        {  
            e.printStackTrace();  
            //讓測試失敗  
            Assert.fail();  
        }  
        //第一個引數是預期的,第二個引數是真實的  
        Assert.assertEquals(2, result);  
          
    }
    
    //除數為0的情況  
    public void testDivideByZero()  
    {  
        Throwable th = null ;  
          
        //Calculator cal = new Calculator();  
        try   
        {  
            cal.divide(1, 0);  
            Assert.fail();  
        }  
        catch(Exception e)  
        {  
            th = e ;  
            //e.printStackTrace();  
        }  
          
        //th 不為空 null  
        Assert.assertNotNull(th);  
        //第一個引數是預期的,第二個引數是真實的  
        Assert.assertEquals(Exception.class, th.getClass());  
        Assert.assertEquals("除數不能為0", th.getMessage());  
          
    }
    
    //加了這個main方法,可以直接以 Java Application 方式執行 ,也可以以 JUnit Test 執行  
    public static void main(String[] args)  
    {  
        //命令列形式列印  
        junit.textui.TestRunner.run(CalculatorTest.class);  
          
        //awt 介面方式顯示  
        //junit.awtui.TestRunner.run(CalculatorTest.class);  
          
        //swing 介面方式顯示  
        //junit.swingui.TestRunner.run(CalculatorTest.class);  
    }

}
複製程式碼

     從上面的程式碼中可以看出Junit測試類是通過繼承一個TestCase類來實現方法的測試,而這就是Junit4.0以前的測試方式,而在4.0之後他們的實現方式又有了稍微的變化。

Junit4.0之後不再是通過繼承TestCase的方式來實現方法的實測,而是採用註解的方式進行的。根據Java 5.0中的新特徵(註解,靜態匯入等),Junit開發團隊也隨之靠攏,採用註解的方式來進行方法的測試。這樣下來相比而言JUnit 4更簡單、更豐富和更易於使用。

        Junit4.0測試類

複製程式碼
package com.junit4_0;

import static org.junit.Assert.assertEquals;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
 * Junit4.0
 * @author CHH
 * @since 2013-01-19 晚上10:12
 *
 */
public class CalculatorTest {

    private static Calculator calculator = new Calculator();

    //每個方法測試前呼叫
    @Before
    public void clearCalculator() {
        calculator.clear();
    }
    
    //每個方法測試完以後呼叫
    @After 
    public void tearDown()  
    {  
         
    }
    
    //@Test:測試方法,表明這是一個測試方法。在Junit中將會自動被執行。
    @Test
    public void add() {
        calculator.add(1);
        calculator.add(1);
        //第一個引數是預期的,第二個引數是真實的  
        assertEquals(calculator.getResult(), 2);
    }

    @Test
    public void subtract() {
        calculator.add(10);
        calculator.substract(2);
        //第一個引數是預期的,第二個引數是真實的  
        assertEquals(calculator.getResult(), 8);
    }

    //給測試函式設定一個執行時間,超過了這個時間(400毫秒),它們就會被系統強行終止
    @Test(timeout=400)
    public void divide() {
        calculator.add(8);
        calculator.divide(2);
        //第一個引數是預期的,第二個引數是真實的  
        assert calculator.getResult() == 5;
    }

    //使用註釋來宣告該異常是預期的,異常測試是Junit4中的最大改進
    @Test(expected = ArithmeticException.class)
    public void divideByZero() {
        calculator.divide(0);
    }

    //@Ignore:忽略的測試方法,標註的含義就是“某些方法尚未完成,暫不參與此次測試”
    @Ignore("not ready yet")
    @Test
    public void multiply() {
        calculator.add(10);
        calculator.multiply(10);
        //第一個引數是預期的,第二個引數是真實的  
        assertEquals(calculator.getResult(), 100);
    }

}
複製程式碼

  Junit4出了採用的註解的方式來進行測試方法之外,還增加了一些新的元素。

     A、JUnit4添加了兩個比較陣列的assert() 方法:

  public static void assertEquals(Object[] expected, Object[] actual)

  public static void assertEquals(String message, Object[] expected, Object[] actual)

  Junit4常用註解:

    @Test  測試方法,表明這是一個測試方法。在Junit中將會自動被執行。

    @Test(timeOut=400)  給測試函式設定一個執行時間,超過了這個時間(400毫秒),它們就會被系統強行終止

    @Test(expected = ArithmeticException.class)  使用註釋來宣告該異常是預期的,異常測試是Junit4中的最大改進

    @Ignore("not ready yet")    忽略的測試方法,標註的含義就是“某些方法尚未完成,暫不參與此次測試”

    @Before   每個方法測試前呼叫

    @After   每個方法測試完以後呼叫

    @BeforeClass   每個類執行前呼叫,並且只調用一次

    @AfterClass  每個類執行後呼叫,並且只調用一次

  表格[email protected]/@AfterClass比較於@Before/@After。

@BeforeClass和@AfterClass @Before和@After
在每個類中只有一個方法能被註解。 多個方法能被註解,但其執行的順序未特別指定,且不執行過載方法。
方法名是不相關的 方法名是不相關的
每個類執行一次 在每個測試方法執行前或執行後執行
在當前類的@BeforeClass方法執行前先執行超類的@BeforeClass方法。在超類中宣告的@AfterClass方法將在所有當前類的該方法執行後才執行。 超類中的@Before在所有子類的該方法執行前執行。在超類中的@After在在所有子類的該方法執行後才執行。
必須是公共和非靜態的。 必須是公共和非靜態的。
即使一個@BeforeClass方法丟擲一個異常,所有的@AfterClass方法也保證被執行。 即使一個@Before或者@Test方法丟擲一個異常,所有的@After方法也保證被執行。

  總結:這兩個版本最大的區別在JUnit3.x中測試必須繼承 TestCase,並且每個方法名必須以test開頭。比如:testMethod1()而在JUnit4.x中不必繼承TestCase,採用了註解的 方式。只要在測試的方法上加上註解@Test即可,從而不必再遵循以前的一些顯式約定和反射定位測試;在JUnit4.x中如果繼承了TestCase, 註解就不起作用了。並且有很重要的一點就是在JUnit4.x中繼承了TestCase後,在OutLine檢視中測試單個方法時,結果整個類都run 了。還有一點就是,在3.x中需要實現setUp和tearDown方法,而在4.x中無需這樣,可以自定義需要在測試前和測試後的方法,在方法前加上 @before,@after就可以了。所以在JUnit4.x不必繼承TestCase用註解即可對單個方法進行測試。