1. 程式人生 > >談談單元測試之(三):測試工具 JUnit 4

談談單元測試之(三):測試工具 JUnit 4


前言


上一篇文章《測試工具 JUnit 3》簡單的討論了 JUnit 3 的使用以及內部的方法。這篇文章將會在 JUnit 3 的基礎上,討論一下 JUnit 4 的新特性。同時,與 JUnit 3 做一個簡單的對比。那麼,廢話就不多說了,直接進入正題。

介紹


JUnit 4.x 是利用了 Java 5 的特性(Annotation)的優勢,使得測試比起 3.x 版本更加的方便簡單,JUnit 4.x 不是舊版本的簡單升級,它是一個全新的框架,整個框架的包結構已經徹底改變,但 4.x 版本仍然能夠很好的相容舊版本的測試用例。


使用


先來點實在的,看看程式碼中是怎麼使用的。其餘的待會再說。

下載



加入專案

  • 把 junit4.8.1.jar 檔案,加入到專案的 classpath 中。


對比


在程式碼之前,先讓我們看一下 JUnit 4 和 JUnit 3 的區別,看看 JUnit 4 到底簡化了哪些東西。




演示程式碼

[java] view plain copy print ?
  1. <span style=“font-family:Microsoft YaHei;”>package com.tgb;  
  2.   
  3. import static org.junit.Assert.*;  
  4.   
  5. import org.junit.Ignore;  
  6. import org.junit.Test;  
  7.   
  8.   
  9. public class TestWordDealUtil {  
  10.     // 測試 wordFormat4DB 正常執行的情況  
  11.     @Test  
  12.     public void testWordFarmat4DBNormal() {  
  13.         String target = ”employeeInfo”;  
  14.         String result = WordDealUtil.wordFormat4DB(target);  
  15.           
  16.         assertEquals(”employee_info”, result);  
  17.     }  
  18.       
  19.     // 測試 null 時的處理情況  
  20.     @Test(expected=NullPointerException.class)  
  21.     public void testWordFormat4DBNull() {  
  22.         String target = null;  
  23.         String result = WordDealUtil.wordFormat4DB(target);  
  24.           
  25.         assertNull(result);  
  26.     }  
  27.       
  28.     // 測試空字串的處理情況  
  29.     @Test  
  30.     public void testWordFormat4DBEmpty() {  
  31.         String target = ”“;  
  32.         String result = WordDealUtil.wordFormat4DB(target);  
  33.           
  34.         assertEquals(”“, result);  
  35.     }  
  36.       
  37.     // 測試當首字母大寫時的情況  
  38.     //@Ignore  
  39.     @Test  
  40.     public void testWordFormat4DBBegin() {  
  41.         String target = ”EmployeeInfo”;  
  42.         String result = WordDealUtil.wordFormat4DB(target);  
  43.           
  44.         assertEquals(”_employee_info”, result);  
  45.     }  
  46.       
  47.     // 測試當尾字母大寫時的情況  
  48.     @Test  
  49.     public void testWordFormat4DBEnd() {  
  50.         String target = ”employeeInfoA”;  
  51.         String result = WordDealUtil.wordFormat4DB(target);  
  52.           
  53.         assertEquals(”employee_info_a”, result);  
  54.     }  
  55.       
  56.     // 測試多個相連字母字母大寫時的情況  
  57.     @Test  
  58.     public void testWordFormat4DBTogether() {  
  59.         String target = ”employeeAInfo”;  
  60.         String result = WordDealUtil.wordFormat4DB(target);  
  61.           
  62.         assertEquals(”employee_a_info”, result);  
  63.     }  
  64. }  
  65. </span>  
<span style="font-family:Microsoft YaHei;">package com.tgb;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;


public class TestWordDealUtil {
    // 測試 wordFormat4DB 正常執行的情況
    @Test
    public void testWordFarmat4DBNormal() {
        String target = "employeeInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_info", result);
    }

    // 測試 null 時的處理情況
    @Test(expected=NullPointerException.class)
    public void testWordFormat4DBNull() {
        String target = null;
        String result = WordDealUtil.wordFormat4DB(target);

        assertNull(result);
    }

    // 測試空字串的處理情況
    @Test
    public void testWordFormat4DBEmpty() {
        String target = "";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("", result);
    }

    // 測試當首字母大寫時的情況
    //@Ignore
    @Test
    public void testWordFormat4DBBegin() {
        String target = "EmployeeInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("_employee_info", result);
    }

    // 測試當尾字母大寫時的情況
    @Test
    public void testWordFormat4DBEnd() {
        String target = "employeeInfoA";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_info_a", result);
    }

    // 測試多個相連字母字母大寫時的情況
    @Test
    public void testWordFormat4DBTogether() {
        String target = "employeeAInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_a_info", result);
    }
}
</span>


從圖中可以看出,TestWordDealUtil 測試類中,有6個測試方法,其中有5個測試方法都已經通過,另外一個丟擲了 NullPointerException (空指標)異常,需要注意的是,這裡並不是單元測試的失敗(Failure),而是測試出現了錯誤(Error)。那麼,這兩種有什麼區別呢?下面就討論一下這兩者的區別。
JUnit 將測試失敗的情況分為兩種:Failure 和 Error 。 Failure 一般是由單元測試使用的斷言方法判斷失敗引起的,它表示在測試點發現了問題(程式中的 bug);而 Error 則是有程式碼異常引起的,這是測試目的之外的發現,它可能產生於測試程式碼本身的錯誤(也就是說,編寫的測試程式碼有問題),也可能是被測試程式碼中的一個隱藏 bug 。不過,一般情況下是第一種情況。

深入


常用註解

  • @Before
初始化方法,在任何一個測試方法執行之前,必須執行的程式碼。對比 JUnit 3 ,和 setUp()方法具有相同的功能。在該註解的方法中,可以進行一些準備工作,比如初始化物件,開啟網路連線等。
  • @After
釋放資源,在任何一個測試方法執行之後,需要進行的收尾工作。對比 JUnit 3 ,和 tearDown()方法具有相同的功能。
  • @Test
測試方法,表明這是一個測試方法。在 JUnit 中將會自動被執行。對與方法的宣告也有如下要求:名字可以隨便取,沒有任何限制,但是返回值必須為 void ,而且不能有任何引數。如果違反這些規定,會在執行時丟擲一個異常。不過,為了培養一個好的程式設計習慣,我們一般在測試的方法名上加 test ,比如:testAdd()。
同時,該 Annotation(@Test) 還可以測試期望異常和超時時間,如 @Test(timeout=100),我們給測試函式設定一個執行時間,超過這個時間(100毫秒),他們就會被系統強行終止,並且系統還會向你彙報該函式結束的原因是因為超時,這樣你就可以發現這些 bug 了。而且,它還可以測試期望的異常,例如,我們剛剛的那個空指標異常就可以這樣:@Test(expected=NullPointerException.class)。再來看一下測試結果。



  • @Ignore
忽略的測試方法,標註的含義就是“某些方法尚未完成,咱不參與此次測試”;這樣的話測試結果就會提示你有幾個測試被忽略,而不是失敗。一旦你完成了相應的函式,只需要把 @Ignore 註解刪除即可,就可以進行正常測試了。當然,這個 @Ignore 註解對於像我這樣有“強迫症”的人還是大有意義的。每當看到紅色條(測試失敗)的時候就會全身不舒服,感覺無法忍受(除非要測試的目的就是讓它失敗)。當然,對程式碼也是一樣,無法忍受那些雜亂不堪的程式碼。所以,建議大家都寫漂亮的程式碼。這樣人人都喜歡看你的程式碼。哎,有強迫症的人傷不起啊!
  • @BeforeClass
針對所有測試,也就是整個測試類中,在所有測試方法執行前,都會先執行由它註解的方法,而且只執行一次。當然,需要注意的是,修飾符必須是 public static void xxxx ;此 Annotation 是 JUnit 4 新增的功能。
  • @AfterClass
針對所有測試,也就是整個測試類中,在所有測試方法都執行完之後,才會執行由它註解的方法,而且只執行一次。當然,需要注意的是,修飾符也必須是 public static void xxxx ;此 Annotation 也是 JUnit 4 新增的功能,與 @BeforeClass 是一對。

執行順序


所以,在 JUnit 4 中,單元測試用例的執行順序為:



每一個測試方法的呼叫順序為:





規範


最後,在來說說關於測試的規範,這些規範是從程式設計規則,以及日常的實踐中,由那些大牛們總結出來的。作為後人的我們,在大樹下乘涼的同時,更要遵守這些規則,使得大樹更加茁壯成長。
  • 單元測試程式碼應位於單獨的 Source Folder 下
此 Source Folder 通常為 test ,這樣可以方便的管理業務程式碼與測試程式碼。其實,在專案管理工具 Maven 上已經做了這種規範了。在我們自己寫程式碼時,注意一下即可。


  • 測試類應該與被測試類位於同一 package 下
便於進行管理,同時減少引入帶測試類的麻煩。



  • 選擇有意義的測試方法名
無論是 JUnit 4 ,還是 JUnit 3 ,單元測試方法名均需使用 test<待測試方法名稱>[概要描述] ,如 public void testDivideDivisorIsZero() ,很容易知道測試方法的含義。
  • 儲存測試的獨立性
每項單元測試都必須獨立於其他所有單元測試而執行,因為單元測試需能以任何順序執行。
  • 為暫時未實現的測試程式碼忽略(@Ignore)或丟擲失敗(fail)
在 JUnit 4 中,可以在測試方法上使用註解 @Ignore 。在 JUnit 3 中,可以在未實現的測試方法中使用 fail(“測試方法未實現”); 以告知失敗是因為測試方法未實現。
  • 在呼叫斷言(assert)方法時給出失敗的原因
在使用斷言方法時,請使用帶有 message 引數的 API ,並在呼叫時給出失敗時的原因描述,如 assertNotNull(”物件為空”, new Object())。

結束語


請牢記:測試任何可能的錯誤。單元測試不是用來證明您是對的,而是為了證明您沒有錯。
JUnit 4 到這裡就差不多了,如果文章中有什麼不對的地方,還希望各位大牛拍磚。說了這麼多,能真正用上才是王道,當然,希望以我這篇文章為契機,IT 界的精英們,之前沒有用單元測試的,能夠喚醒你們體內的小宇宙;之前已經在用的,也能夠再體會一番,提高開發的效率,寫出 漂亮 的程式碼。

資料:本文中的Demo下載地址

【原創】地址:http://blog.csdn.net/happylee6688/article/details/38069761這裡寫連結內容


前言


上一篇文章《測試工具 JUnit 3》簡單的討論了 JUnit 3 的使用以及內部的方法。這篇文章將會在 JUnit 3 的基礎上,討論一下 JUnit 4 的新特性。同時,與 JUnit 3 做一個簡單的對比。那麼,廢話就不多說了,直接進入正題。

介紹


JUnit 4.x 是利用了 Java 5 的特性(Annotation)的優勢,使得測試比起 3.x 版本更加的方便簡單,JUnit 4.x 不是舊版本的簡單升級,它是一個全新的框架,整個框架的包結構已經徹底改變,但 4.x 版本仍然能夠很好的相容舊版本的測試用例。

使用


先來點實在的,看看程式碼中是怎麼使用的。其餘的待會再說。

下載



加入專案

  • 把 junit4.8.1.jar 檔案,加入到專案的 classpath 中。


對比


在程式碼之前,先讓我們看一下 JUnit 4 和 JUnit 3 的區別,看看 JUnit 4 到底簡化了哪些東西。



演示程式碼

[java] view plain copy print ?
  1. <span style=“font-family:Microsoft YaHei;”>package com.tgb;  
  2.   
  3. import static org.junit.Assert.*;  
  4.   
  5. import org.junit.Ignore;  
  6. import org.junit.Test;  
  7.   
  8.   
  9. public class TestWordDealUtil {  
  10.     // 測試 wordFormat4DB 正常執行的情況  
  11.     @Test  
  12.     public void testWordFarmat4DBNormal() {  
  13.         String target = ”employeeInfo”;  
  14.         String result = WordDealUtil.wordFormat4DB(target);  
  15.           
  16.         assertEquals(”employee_info”, result);  
  17.     }  
  18.       
  19.     // 測試 null 時的處理情況  
  20.     @Test(expected=NullPointerException.class)  
  21.     public void testWordFormat4DBNull() {  
  22.         String target = null;  
  23.         String result = WordDealUtil.wordFormat4DB(target);  
  24.           
  25.         assertNull(result);  
  26.     }  
  27.       
  28.     // 測試空字串的處理情況  
  29.     @Test  
  30.     public void testWordFormat4DBEmpty() {  
  31.         String target = ”“;  
  32.         String result = WordDealUtil.wordFormat4DB(target);  
  33.           
  34.         assertEquals(”“, result);  
  35.     }  
  36.       
  37.     // 測試當首字母大寫時的情況  
  38.     //@Ignore  
  39.     @Test  
  40.     public void testWordFormat4DBBegin() {  
  41.         String target = ”EmployeeInfo”;  
  42.         String result = WordDealUtil.wordFormat4DB(target);  
  43.           
  44.         assertEquals(”_employee_info”, result);  
  45.     }  
  46.       
  47.     // 測試當尾字母大寫時的情況  
  48.     @Test  
  49.     public void testWordFormat4DBEnd() {  
  50.         String target = ”employeeInfoA”;  
  51.         String result = WordDealUtil.wordFormat4DB(target);  
  52.           
  53.         assertEquals(”employee_info_a”, result);  
  54.     }  
  55.       
  56.     // 測試多個相連字母字母大寫時的情況  
  57.     @Test  
  58.     public void testWordFormat4DBTogether() {  
  59.         String target = ”employeeAInfo”;  
  60.         String result = WordDealUtil.wordFormat4DB(target);  
  61.           
  62.         assertEquals(”employee_a_info”, result);  
  63.     }  
  64. }  
  65. </span>  
<span style="font-family:Microsoft YaHei;">package com.tgb;

import static org.junit.Assert.*;

import org.junit.Ignore;
import org.junit.Test;


public class TestWordDealUtil {
    // 測試 wordFormat4DB 正常執行的情況
    @Test
    public void testWordFarmat4DBNormal() {
        String target = "employeeInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_info", result);
    }

    // 測試 null 時的處理情況
    @Test(expected=NullPointerException.class)
    public void testWordFormat4DBNull() {
        String target = null;
        String result = WordDealUtil.wordFormat4DB(target);

        assertNull(result);
    }

    // 測試空字串的處理情況
    @Test
    public void testWordFormat4DBEmpty() {
        String target = "";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("", result);
    }

    // 測試當首字母大寫時的情況
    //@Ignore
    @Test
    public void testWordFormat4DBBegin() {
        String target = "EmployeeInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("_employee_info", result);
    }

    // 測試當尾字母大寫時的情況
    @Test
    public void testWordFormat4DBEnd() {
        String target = "employeeInfoA";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_info_a", result);
    }

    // 測試多個相連字母字母大寫時的情況
    @Test
    public void testWordFormat4DBTogether() {
        String target = "employeeAInfo";
        String result = WordDealUtil.wordFormat4DB(target);

        assertEquals("employee_a_info", result);
    }
}
</span>


從圖中可以看出,TestWordDealUtil 測試類中,有6個測試方法,其中有5個測試方法都已經通過,另外一個丟擲了 NullPointerException (空指標)異常,需要注意的是,這裡並不是單元測試的失敗(Failure),而是測試出現了錯誤(Error)。那麼,這兩種有什麼區別呢?下面就討論一下這兩者的區別。
JUnit 將測試失敗的情況分為兩種:Failure 和 Error 。 Failure 一般是由單元測試使用的斷言方法判斷失敗引起的,它表示在測試點發現了問題(程式中的 bug);而 Error 則是有程式碼異常引起的,這是測試目的之外的發現,它可能產生於測試程式碼本身的錯誤(也就是說,編寫的測試程式碼有問題),也可能是被測試程式碼中的一個隱藏 bug 。不過,一般情況下是第一種情況。

深入


常用註解

  • @Before
初始化方法,在任何一個測試方法執行之前,必須執行的程式碼。對比 JUnit 3 ,和 setUp()方法具有相同的功能。在該註解的方法中,可以進行一些準備工作,比如初始化物件,開啟網路連線等。
  • @After
釋放資源,在任何一個測試方法執行之後,需要進行的收尾工作。對比 JUnit 3 ,和 tearDown()方法具有相同的功能。
  • @Test
測試方法,表明這是一個測試方法。在 JUnit 中將會自動被執行。對與方法的宣告也有如下要求:名字可以隨便取,沒有任何限制,但是返回值必須為 void ,而且不能有任何引數。如果違反這些規定,會在執行時丟擲一個異常。不過,為了培養一個好的程式設計習慣,我們一般在測試的方法名上加 test ,比如:testAdd()。
同時,該 Annotation(@Test) 還可以測試期望異常和超時時間,如 @Test(timeout=100),我們給測試函式設定一個執行時間,超過這個時間(100毫秒),他們就會被系統強行終止,並且系統還會向你彙報該函式結束的原因是因為超時,這樣你就可以發現這些 bug 了。而且,它還可以測試期望的異常,例如,我們剛剛的那個空指標異常就可以這樣:@Test(expected=NullPointerException.class)。再來看一下測試結果。



  • @Ignore
忽略的測試方法,標註的含義就是“某些方法尚未完成,咱不參與此次測試”;這樣的話測試結果就會提示你有幾個測試被忽略,而不是失敗。一旦你完成了相應的函式,只需要把 @Ignore 註解刪除即可,就可以進行正常測試了。當然,這個 @Ignore 註解對於像我這樣有“強迫症”的人還是大有意義的。每當看到紅色條(測試失敗)的時候就會全身不舒服,感覺無法忍受(除非要測試的目的就是讓它失敗)。當然,對程式碼也是一樣,無法忍受那些雜亂不堪的程式碼。所以,建議大家都寫漂亮的程式碼。這樣人人都喜歡看你的程式碼。哎,有強迫症的人傷不起啊!
  • @BeforeClass
針對所有測試,也就是整個測試類中,在所有測試方法執行前,都會先執行由它註解的方法,而且只執行一次。當然,需要注意的是,修飾符必須是 public static void xxxx ;此 Annotation 是 JUnit 4 新增的功能。
  • @AfterClass
針對所有測試,也就是整個測試類中,在所有測試方法都執行完之後,才會執行由它註解的方法,而且只執行一次。當然,需要注意的是,修飾符也必須是 public static void xxxx ;此 Annotation 也是 JUnit 4 新增的功能,與 @BeforeClass 是一對。

執行順序


所以,在 JUnit 4 中,單元測試用例的執行順序為:



每一個測試方法的呼叫順序為:





規範


最後,在來說說關於測試的規範,這些規範是從程式設計規則,以及日常的實踐中,由那些大牛們總結出來的。作為後人的我們,在大樹下乘涼的同時,更要遵守這些規則,使得大樹更加茁壯成長。
  • 單元測試程式碼應位於單獨的 Source Folder 下
此 Source Folder 通常為 test ,這樣可以方便的管理業務程式碼與測試程式碼。其實,在專案管理工具 Maven 上已經做了這種規範了。在我們自己寫程式碼時,注意一下即可。


  • 測試類應該與被測試類位於同一 package 下
便於進行管理,同時減少引入帶測試類的麻煩。



  • 選擇有意義的測試方法名
無論是 JUnit 4 ,還是 JUnit 3 ,單元測試方法名均需使用 test<待測試方法名稱>[概要描述] ,如 public void testDivideDivisorIsZero() ,很容易知道測試方法的含義。
  • 儲存測試的獨立性
每項單元測試都必須獨立於其他所有單元測試而執行,因為單元測試需能以任何順序執行。
  • 為暫時未實現的測試程式碼忽略(@Ignore)或丟擲失敗(fail)
在 JUnit 4 中,可以在測試方法上使用註解 @Ignore 。在 JUnit 3 中,可以在未實現的測試方法中使用 fail(“測試方法未實現”); 以告知失敗是因為測試方法未實現。
  • 在呼叫斷言(assert)方法時給出失敗的原因
在使用斷言方法時,請使用帶有 message 引數的 API ,並在呼叫時給出失敗時的原因描述,如 assertNotNull(”物件為空”, new Object())。

結束語


請牢記:測試任何可能的錯誤。單元測試不是用來證明您是對的,而是為了證明您沒有錯。
JUnit 4 到這裡就差不多了,如果文章中有什麼不對的地方,還希望各位大牛拍磚。說了這麼多,能真正用上才是王道,當然,希望以我這篇文章為契機,IT 界的精英們,之前沒有用單元測試的,能夠喚醒你們體內的小宇宙;之前已經在用的,也能夠再體會一番,提高開發的效率,寫出 漂亮 的程式碼。

資料:本文中的Demo下載地址

【原創】地址:http://blog.csdn.net/happylee6688/article/details/38069761這裡寫連結內容