JUnit簡單使用教程

jopen 11年前發布 | 79K 次閱讀 JUnit 單元測試

JUnit簡介

       JUnit是由 Erich GammaKent Beck編寫的一個回歸測試框架(regression testing framework)JUnit測試是程序員測試,即所謂白盒測試,因為程序員知道被測試的軟件如何(How)完成功能和完成什么樣(What)的功能。

簡單編寫單元測試實例

public class JunitAnnotation {

    // execute before class
    @BeforeClass
    public static void beforeClass() {
        System.out.println("in before class");
    }

    // execute after class
    @AfterClass
    public static void afterClass() {
        System.out.println("in after class");
    }

    // execute before test
    @Before
    public void before() {
        System.out.println("in before");
    }

    // execute after test
    @After
    public void after() {
        System.out.println("in after");
    }

    // test case
    @Test
    public void test() {
        System.out.println("in test");
    }

    // test case ignore and will not execute
    @Ignore(“unimplemented”)
    public void ignoreTest() {
        System.out.println("in ignore test");
    }
}

JUnit常用注解介紹

      @TestJUnit 3.x是通過對測試方法的命名(test+方法名)來確定是否是測試,且所有的測試類必須繼承TestCaseJUnit 4.x只需要在方法前加上@Test 就可以定義一個測試方法。

      注意:測試方法必須是public void,即公共、無返回值的;可以拋出異常

      @Ignore :該注解標記的測試方法在測試中會被忽略當測試的方法還沒有實現,或者測試的方法已經過時,或者在某種條件下才能測試該方法(比如需要一個數據庫連接,而在本地測試的時候,數據庫并沒有連接),那么使用該注解來標記這個方法。同時可以為該注解傳遞一個String的參數,表明為什么會忽略這個測試方法。比如:@lgnore(“該方法還沒有實現”),在執行的時候,僅會報告該方法沒有實現,而不會運行測試方法。

      @BeforeClass:當我們運行幾個有關聯的用例時,可能會在數據準備或其它前期準備中執行一些相同的命令,這個時候為了讓代碼更清晰,更少冗余,可以將公用的部分提取出來, 放在一個方法里,并為這個方法注解@BeforeClass。意思是在測試類里所有用例運行之前,運行一次這個方法。例如創建數據庫連接、讀取文件等。

      注意:方法名可以任意,但必須是public static void,即公開的、靜態的、無返回值的。這個方法只會運行一次。

      @AfterClass:跟@BeforeClass對應,在測試類里所有用例運行之后,運行一次。用于處理一些測試后續工作,例如清理數據,恢復現場。

      注意:同樣必須是public static void,即公開的、靜態的、無返回值的。這個方法只會運行一次。

      @Before:使用了該注解的方法在每個測試方法執行之前都要執行一次。主要用于一些獨立于用例之間的準備工作。比如兩個用例都需要讀取數據庫里的用戶A信息,但第一個用例會刪除這個用戶A,而第二個用例需要修改用戶A。那么可以用@BeforeClass創建數據庫連接。用@Before來插入一條用戶A信息。

      注意:必須是public void,不能為static

      @After :使用了該注解的方法在每個測試方法執行之后要執行一次。

      @Runwith:即測試運行器,放在測試類名之前,用來確定測試類怎么運行的,當不指定這個注解時,使用默認Runner來運行測試代碼,@RunWith(JUnit4.class)

      常見的運行器有:

      (1)@RunWith(Parameterized.class):參數化運行器,配合@Parameters使用JUnit的參數化功能。

      (2)@RunWith(Suite.class)

         @SuiteClasses({ATest.class,BTest.class,CTest.class})

          測試集運行器配合使用測試集功能。    

      (3)@RunWith(JUnit4.class)JUnit 4的默認運行器

      (4)@RunWith(JUnit38ClassRunner.class):用于兼容junit3.8的運行器

      (5)一些其它運行器具備更多功能。例如@RunWith(SpringJUnit4ClassRunner.class)集成了Spring的一些功能。

      @Parameters:用于JUnit的參數化功能,用來標記準備數據的方法。

       注意:該方法需要滿足一定的要求: 

              (1)該方法必須為public static

              (2)該方法返回值必須為java.util.Collection類型 

              (3)該方法的名字不做要求 

              (4)該方法沒有參數 

參數化測試

      為了保證單元測試的嚴謹性,我們模擬了不同的測試數據來測試方法的處理能力,為此我們編寫了大量的單元測試方法。而這些測試方法大同小異:代碼結構都是相同的,不同的僅僅是測試數據和期望值。為了降低代碼的冗余,JUnit 4提供了參數化測試,即只寫一個測試方法,把這若干種情況作為參數傳遞進去,一次性的完成測試。 

     JUnit 4參數化測試的五個步驟:

     (1)為準備使用參數化測試的測試類指定特殊的運行器org.junit.runners.Parameterized。

     (2)為測試類聲明幾個變量,分別用于存放期望值和測試所用數據。

     (3)為測試類聲明一個帶有參數的公共構造函數,并在其中為第二個環節中聲明的幾個變量賦值。

     (4)為測試類聲明一個使用注解 org.junit.runners.Parameterized.Parameters飾的,返回值為java.util.Collection的公共靜態方法,并在此方法中初始化所有需要測試的參數對。

    (5)編寫測試方法,使用定義的變量作為參數進行測試。

    Demo如下:

@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());
    }
 }

打包測試

       在一個項目中,只寫一個測試類是不可能的,我們會寫出很多很多個測試類。可是這些測試類必須一個一個的執行,也是比較麻煩的事情。鑒于此,JUnit為我們提供了打包測試的功能,將所有需要運行的測試類集中起來,一次性的運行完畢,大大的方便了我們的測試工作。具體代碼如下:

@RunWith(Suite.class)
@Suite.SuiteClasses({ CalculatorTest.class,SquareTest.class})
public class AllCalculatorTests{
}

      大家可以看到,這個功能也需要使用一個特殊的Runner,因此我們需要向@RunWith注解傳遞一個參數Suite.class。同時,我們還需要另外一個注解@Suite.SuiteClasses,來表明這個類是一個打包測試類。我們把需要打包的類作為參數傳遞給該注解就可以了。有了這兩個注解之后,就已經完整的表達了所有的含義,因此下面的類已經無關緊要,隨便起一個類名,內容全部為空既可。

異常測試

       JUnit 4之前,對錯誤的測試,我們只能通過fail來產生一個錯誤,并在try塊里面assertTrue(true)來測試。現在,可以通過@Test 注解中的expected屬性來測試異常。expected屬性的值是一個異常的類型。

       Demo如下:

@Test(expected=ArithmeticException.class)
public void testDivide() {
    new Calculator().divide(6, 0);
}

限時測試

      對于那些邏輯很復雜,循環嵌套比較深的程序,很有可能出現死循環,因此一定要采取一些預防措施。限時測試是一個很好的解決方案。我們給這些測試方法設定一個執行時間,超過了這個時間,他們就會被系統強行終止,并且系統還會向你匯報該方法結束的原因是因為超時,這樣你就可以發現這些Bug了。要實現這一功能,只需要給@Test 注解加一個timeout屬性,該注解傳入了一個時間(毫秒)給測試方法,如果測試方法在指定的時間之內沒有運行完,則測試失敗。

      Demo如下:   

@Test(timeout=1000)
public void testDeathLoop() {
    new Calculator().deathLoop();
}

         單元測試運行結果:java.lang.Exception: test timed out after 1000 milliseconds

         at test.Calculator.deathLoop(Calculator.java:25)

         at test.CaculatorTest.testDeathLoop(CaculatorTest.java:26)

         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)

         …………………………

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!