<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    使用 JUnit 進行 Java 代碼的單元測試

      下載安裝 JUnit 的相關文件
      首先我們需要先下載相應的 JUnit 相關的 JAR 包,下載的過程可以去 JUnit 的官方網站,也可以直接通過 Maven 資源倉庫來完成,我這里直接通過開源中國社區在國內的Maven 鏡像下載了 JUnit-4.8.2.jar 的版本,如下圖所示:
      直接搜索關鍵字"junit"即可,我們可以從搜索結果中找到紅色方框1中的對應項,選中之后就會在左下方列出目前可以獲得的 junit  的所有版本,這里我選擇了 4.8.2 的版本(紅色方框2),然后點擊右側的 Download 按鈕即可下載這個 JAR 包,不過依我在實踐中的經驗,最好同時下載對應版本的 javadoc 和 source 兩個包,前者是文檔,后者是對應的源代碼,然后將它們直接引入到我們的 eclipse 的工程中即可。我這里創建了壹個普通的 Java Project ,并給它取名 junit-study ,導入 JAR 包之后目前的樣子如下圖所示:
      使用簡單的 @Test 注解實現我們的測試方法的編寫和執行
      準備工作做好之后,接下來我們就可以開始嘗試編寫壹個簡單的測試代碼了。首先,我們編寫了壹個 Calculator 類,并提供五個方法分別完成加減乘除以及求平方的運算。代碼如下:
    package net.oschina.bairrfhoinn.main;
    public class Calculator {
    public void add(int n){
    result += n;
    }
    public void substract(int n){
    result -= n;
    }
    public void multiply(int n){
    result *= n;
    }
    public void divide(int n){
    result /= n;
    }
    public void square(int n){
    result = n * n;
    }
    public int getReuslt(){
    return result;
    }
    public void clear(){
    result = 0;
    }
    private static int result;
    }
      在測試類中用到了JUnit4框架,自然要把相應地Package包含進來。最主要地一個Package就是org.junit.*。把它包含進來之后,絕大部分功能就有了。還有一句話也非常地重要“import static org.junit.Assert.*;”,我們在測試的時候使用的壹系列assertEquals()方法就來自這個包。大家注意壹下,這是壹個靜態包含(static),是JDK5中新增添的壹個功能。也就是說,assertEquals是Assert類中的壹系列的靜態方法,壹般的使用方式是Assert. assertEquals(),但是使用了靜態包含后,前面的類名就可以省略了,使用起來更加的方便。
      另外要注意的是,我們的測試類是壹個獨立的類,沒有任何父類。測試類的名字也可以任意命名,沒有任何局限性。所以我們不能通過類的聲明來判斷它是不是一個測試類,它與普通類的區別在于它內部的方法的聲明,我們接著會講到。在測試類中,并不是每壹個方法都是用于測試的,所以我們必須使用“注解”來明確表明哪些是測試方法。“注解”也是JDK5的壹個新特性,用在此處非常恰當。我們可以看到,在某些方法的前有@Before、@Test、@Ignore等字樣,這些就是注解,以壹個“@”作為開頭。這些注解都是JUnit4自定義的,熟練掌握這些注解的含義,對于編寫恰當的測試類非常重要。
     接下來我們創建壹個測試類 CalculatorTest.java,代碼如下:
    package net.oschina.bairrfhoinn.test;
    import static org.junit.Assert.*;
    import org.junit.Test;
    import net.oschina.bairrfhoinn.main.Calculator;
    public class CalculatorTest {
    private static Calculator calculator = new Calculator();
    @Test
    public void testAdd(){
    calculator.add(7);
    calculator.add(8);
    assertEquals(15, calculator.getReuslt());
    }
    }
      首先,我們要在方法的前面使用@Test標注,以表明這是壹個測試方法。對于方法的聲明也有如下要求:名字可以隨便取,沒有任何限制,但是返回值必須為void,而且不能有任何參數。如果違反這些規定,會在運行時拋出壹個異常。至于方法內該寫些什么,那就要看你需要測試些什么了。比如上述代碼中,我們想測試壹下add()方法的功能是否正確,就在測試方法中調用幾次add函數,初始值為0,先加7,再加8,我們期待的結果應該是15。如果最終實際結果也是15,則說明add()方法是正確的,反之說明它是錯的。assertEquals(15, calculator.getResult());就是用來判斷期待結果和實際結果是否相等,其中第壹個參數填寫期待結果,第二個參數填寫實際結果,也就是通過計算得到的結果。這樣寫好之后,JUnit 會自動進行測試并把測試結果反饋給用戶。
      如果想運行它,可以在 eclipse 的資源管理器中選擇該類文件,然后點擊右鍵,選擇 Run As->JUnit Test 即可看到運行結果如下圖所示:
      使用@Test 的屬性 Ignore 指定測試時跳過這個方法
      如果你在寫程序前做了很好的規劃,那么哪些方法是什么功能都應該實現并且確定下來。因此,即使該方法尚未完成,他的具體功能也是確定的,這也就意味著你可以為他編寫測試用例。但是,如果你已經把該方法的測試用例寫完,但該方法尚未完成,那么測試的時候無疑是“失敗”。這種失敗和真正的失敗是有區別的,因此 JUnit 提供了壹種方法來區別他們,那就是在這種測試函數的前面加上 @Ignore 標注,這個標注的含義就是“某些方法尚未完成,暫不參與此次測試”。這樣的話測試結果就會提示你有幾個測試被忽略,而不是失敗。壹旦你完成了相應函數,只需要把@Ignore標注刪去,就可以進行正常的測試。
      比如說上面的測試類 Calculator.java 中,假設我們的 Calculator 類的 multiply() 方法沒有實現,我們可以在測試類 CalculatorTest 中先寫如下測試代碼:
    package net.oschina.bairrfhoinn.test;
    import static org.junit.Assert.*;
    import org.junit.Ignore;
    import org.junit.Test;
    import net.oschina.bairrfhoinn.main.Calculator;
    public class CalculatorTest {
    private static Calculator calculator = new Calculator();
    ... //此處代碼省略
    @Ignore("method square() not implemented, please test this later...")
    @Test
    public void testSquare(){
    calculator.square(3);
    assertEquals(9, calculator.getReuslt());
    }
    }
      我們再運行壹次測試,會看到如下結果,從圖中可以很明顯的看出,方法testSquare() 上的 @Ignore 注解已經生效了,運行時直接跳過了它,而方法testAdd()仍然正常的運行并通過了測試。
      使用注解 @Before 和 @After 來完成前置工作和后置工作
      前置工作通常是指我們的測試方法在運行之前需要做的壹些準備工作,如數據庫的連接、文件的加載、輸入數據的準備等需要在運行測試方法之前做的事情,都屬于前置工作;類似的,后置工作則是指測試方法在運行之后的壹些要做的事情,如釋放數據庫連接、輸入輸出流的關閉等;比如我們上面的測試,由于只聲明了壹個 Calculator 對象,他的初始值是0,但是測試完加法操作后,他的值就不是0了;接下來測試減法操作,就必然要考慮上次加法操作的結果。這絕對是壹個很糟糕的設計!我們非常希望每壹個測試方法都是獨立的,相互之間沒有任何耦合度。因此,我們就很有必要在執行每壹個測試方法之前,對Calculator對象進行壹個“復原”操作,以消除其他測試造成的影響。因此,“在任何壹個測試方法執行之前必須執行的代碼”就是壹個前置工作,我們用注解 @Before 來標注它,如下例子所示:
    package net.oschina.bairrfhoinn.test;
    ...
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Ignore;
    import org.junit.Test;
    public class CalculatorTest {
    ...//這里省略部分代碼
    @Before
    public void setUp() throws Exception {
    calculator.clear();
    }
    @After
    public void tearDown() throws Exception {
    System.out.println("will do sth here...");
    }
    ...//這里省略部分代碼
    }
     另外要說的是,注解 @Before 是定義在 org.junit.Before 這個類中的,因此使用時需要將其引入我們的代碼中。這樣做了之后,每次我們運行測試方法時,JUnit 都會先運行 setUp() 方法將 result 的值清零。不過要注意的是,這里不再需要 @Test 注解,因為這并不是壹個 test,只是壹個前置工作。同理,如果“在任何測試執行之后需要進行的收尾工作,我們應該使用 @After 來標注,方法與它類似。由于本例比較簡單,不需要用到此功能,所以我們只是簡單了給它添加了壹個 tearDown() 方法并在收尾時打印壹句話到控制臺,并且使用 @After 來注解這個方法。
      使用@BeforeClass 和 @AfterClass 來完成只需要執行壹次的前置工作和后置工作
      上面我們提到了兩個注解 @Before 和 @After ,我們來看看他們是否適合完成如下功能:有壹個類負責對大文件(超過500 MB)進行讀寫,他的每壹個方法都是對文件進行操作。換句話說,在調用每壹個方法之前,我們都要打開壹個大文件并讀入文件內容,這絕對是壹個非常耗費時的操作。如果我們使用 @Before 和 @After ,那么每次測試都要讀取壹次文件,效率及其低下。所以我們希望的是,在所有測試壹開始讀壹次文件,所有測試結束之后釋放文件,而不是每次測試都讀文件。JUnit的作者顯然也考慮到了這個問題,它給出了@BeforeClass 和 @AfterClass 兩個注解來幫我們實現這個功能。從名字上就可以看出,用這兩個注解標注的函數,只在測試用例初始化時執行 @BeforeClass 方法,當所有測試執行完畢之后,執行 @AfterClass 進行收尾工作。在這里要注意壹下,每個測試類只能有壹個方法被標注為 @BeforeClass 或 @AfterClass,而且該方法必須是 public static 類型的。
      使用@Test 的屬性 timeout 來完成限時測試,以檢測代碼中的死循環
      現在假設我們的 Calculator 類中的 square() 方法是個死循環,那應該怎么辦呢,比如說像下面這樣:
    public void square(int n){
    for(;;){}
    }
      如果測試的時候遇到死循環,你的臉上絕對不會露出笑容的。因此,對于那些邏輯很復雜,循環嵌套比較深的、有可能出現死循環的程序,因此壹定要采取壹些預防措施。限時測試是壹個很好的解決方案。我們給這些測試函數設定壹個預期的執行時間,超過了這壹時間,他們就會被系統強行終止,并且系統還會向你匯報該函數結束的原因是因為超時,這樣你就可以發現這些 Bug 了。要實現這壹功能,只需要給 @Test 標注加壹個參數timeout即可,代碼如下:
    @Test(timeout=2000L)
    public void testSquare() {
    calculator.square(3);
    assertEquals(9, calculator.getReuslt());
    }
      timeout參數表明了你預計該方法運行的時長,單位為毫秒,因此2000就代表2秒。現在我們讓這個測試方法運行壹下,看看失敗時是什么效果。
      使用@Test 的屬性expected來監控測試方法中可能會拋出的某些異常
      JAVA中的異常處理也是壹個重點,因此你經常會編寫壹些需要拋出異常的函數。如果你覺得壹個函數應該拋出異常,但是它沒拋出,這算不算 Bug 呢?這當然是Bug,JUnit 也考慮到了這壹點,并且可以幫助我們找到這種 Bug。例如,我們寫的計算器類有除法功能,如果除數是壹個0,那么必然要拋出“除0異常”。因此,我們很有必要對這些進行測試。代碼如下:
    @Test(expected=java.lang.ArithmeticException.class)
    public void testDivide(){
    calculator.divide(0);
    }
      如上述代碼所示,我們需要使用@Test注解中的expected屬性,將我們要檢驗的異常(這里是 java.lang.ArithmeticException)傳遞給他,這樣 JUnit 框架就能自動幫我們檢測是否拋出了我們指定的異常。
      指定 JUnit 運行測試用例時的 Runner
      大家有沒有想過這個問題,當你把測試代碼提交給JUnit框架后,框架是如何來運行你的代碼的呢?答案就是Runner。在JUnit中有很多個Runner,他們負責調用你的測試代碼,每壹個Runner都有其各自的特殊功能,你要根據需要選擇不同的Runner來運行你的測試代碼。可能你會覺得奇怪,前面我們寫了那么多測試,并沒有明確指定壹個Runner啊?這是因為JUnit中有壹個默認的Runner,如果你沒有指定,那么系統會自動使用默認Runner來運行你的代碼。換句話說,下面兩段代碼含義是完全壹樣的:
    import org.junit.runner.RunWith;
    import org.junit.runners.JUnit4;
    @RunWith(JUnit4.class)
    public class CalculatorTest {
    ...//省略此處代碼
    }
    //用了系統默認的JUnit4.class,運行效果完全壹樣
    public class CalculatorTest {
    ...//省略此處代碼
    }



     從上述例子可以看出:
      1、要想指定壹個 Runner ,需要使用 @RunWith 標注,并且把你所指定的 Runner 類名作為參數傳遞給它,在JUnit4.8.2的版本中,系統提供了若干可以直接使用的Runner類型,它們的定義都在包org.junit.runners下面。
      2、注解 @RunWith 是用來修飾類的,而不是用來修飾函數的。只要對壹個類指定了 Runner ,那么這個類中的所有函數都被這個 Runner 來調用。
      3、在使用注解@RunWith時,要在頭部包含相應的包名,上面的例子對這壹點寫的很清楚了。
      接下來,我會向你們展示其他 Runner 的特有功能。
      使用參數化測試完成需要錄入大量數據的測試
      你可能遇到過這樣的函數,它的參數有許多特殊值,或者說他的參數分為很多個區域。比如,壹個對考試分數進行評價的函數,返回值分別為“優秀,良好,壹般,及格,不及格”,因此你在編寫測試的時候,至少要寫5個測試,把這五種情況都包含了,這確實是壹件很麻煩的事情。這里我們仍然使用先前的例子,測試壹下square()這個函數,暫且分三類:正數、0、負數。測試代碼如下:
    package net.oschina.bairrfhoinn.test;
    import static org.junit.Assert.*;
    import net.oschina.bairrfhoinn.main.Calculator;
    import org.junit.Before;
    import org.junit.Test;
    public class AdvancedTest {
    private static Calculator calculator = new Calculator();
    @Before
    public void setUp() throws Exception {
    calculator.clear();
    }
    @Test
    public void testSquare1(){
    calculator.square(2);
    assertEquals(4, calculator.getReuslt());
    }
    @Test
    public void testSquare2(){
    calculator.square(0);
    assertEquals(0, calculator.getReuslt());
    }
    @Test
    public void testSquare3(){
    calculator.square(-3);
    assertEquals(9, calculator.getReuslt());
    }
    }
      為了簡化類似的測試,JUnit4提出了“參數化測試”的概念,只寫壹個測試函數,把這若干種情況的輸入參數和預期的運行結果放在集合中,然后將這個集合作為參數傳遞進去,壹次性的完成測試。代碼如下:
    package net.oschina.bairrfhoinn.test;
    import static org.junit.Assert.*;
    import java.util.Arrays;
    import java.util.Collection;
    import net.oschina.bairrfhoinn.main.Calculator;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.junit.runners.Parameterized;
    import org.junit.runners.Parameterized.Parameters;
    @RunWith(Parameterized.class)
    public class SquareTest {
    @Parameters
    public static Collection prepareData(){
    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.getReuslt());
    }
    private int param;
    private int result;
    private static Calculator calculator = new Calculator();
    }

    posted on 2013-10-15 11:29 順其自然EVO 閱讀(12154) 評論(2)  編輯  收藏

    評論

    # re: 使用 JUnit 進行 Java 代碼的單元測試[未登錄] 2015-08-31 10:39 1

    1  回復  更多評論   

    # re: 使用 JUnit 進行 Java 代碼的單元測試[未登錄] 2016-08-11 10:54 carry

    test  回復  更多評論   


    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2016年8月>
    31123456
    78910111213
    14151617181920
    21222324252627
    28293031123
    45678910

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 久久久久亚洲av成人无码电影 | 69pao强力打造免费高清| 免费三级毛片电影片| 一区国严二区亚洲三区| 亚洲欧洲第一a在线观看| 亚洲成在人线在线播放无码| a毛片久久免费观看| 成人性生交大片免费看无遮挡 | 国产V亚洲V天堂A无码| 亚洲www77777| 永久免费av无码入口国语片| 免费做爰猛烈吃奶摸视频在线观看| 国产亚洲精品无码拍拍拍色欲| 亚洲伊人久久大香线焦| 羞羞视频免费网站在线看| 成人免费看片又大又黄| 亚洲第一AV网站| 免费很黄无遮挡的视频毛片| 18禁止观看免费私人影院| 亚洲日本乱码在线观看| 亚洲AV无码一区二区乱子仑 | 好吊妞998视频免费观看在线| 亚洲精品乱码久久久久66| 亚洲日韩国产AV无码无码精品| 免费人成黄页在线观看日本| 免费国产成人高清在线观看麻豆| 亚洲熟妇无码久久精品| 亚洲午夜日韩高清一区| 四虎一区二区成人免费影院网址| 91成人免费观看| 亚洲国产成人久久综合区| 亚洲无吗在线视频| 免费A级毛片无码A∨中文字幕下载| 亚洲高清最新av网站| 亚洲人成电影网站色www| 日本免费一区二区在线观看| 久久亚洲国产欧洲精品一| 无码AV动漫精品一区二区免费| 天天摸夜夜摸成人免费视频| 亚洲精品亚洲人成在线麻豆| 免费看少妇高潮成人片|