菜鳥學Java(二十一)——如何更好的進行單元測試——JUnit

劉水鏡發表於2014-06-18

測試在軟體生命週期中的重要性,不用我多說想必大家也都非常清楚。軟體測試有很多分類,從測試的方法上可分為:黑盒測試、白盒測試、靜態測試、動態測試等;從軟體開發的過程分為:單元測試、整合測試、確認測試、驗收、迴歸等。


在眾多的分類中,與開發人員關係最緊密的莫過於單元測試了。像其他種類的測試基本上都是由專門的測試人員來完成,只有單元測試是完全由開發人員來完成的。那麼今天我們就來說說什麼是單元測試,為什麼要進行單元測試,以及如更好的何進行單元測試。


什麼是單元測試?

單元測試(unit testing),是指對軟體中的最小可測試單元進行檢查和驗證。比如我們可以測試一個類,或者一個類中的一個方法。


為什麼要進行單元測試?

為什麼要進行單元測試?說白了就是單元測試有什麼好處,其實測試的好處無非就是減少bug、提高程式碼質量、使程式碼易於維護等。單元測試有什麼好處請看一下百度百科中歸納的四條:


1、它是一種驗證行為。
程式中的每一項功能都是測試來驗證它的正確性。它為以後的開發提供支援。就算是開發後期,我們也可以輕鬆的增加功能或更改程式結構,而不用擔心這個過程中會破壞重要的東西。而且它為程式碼的重構提供了保障。這樣,我們就可以更自由的對程式進行改進。


2、它是一種設計行為。
編寫單元測試將使我們從呼叫者觀察、思考。特別是先寫測試(test-first),迫使我們把程式設計成易於呼叫和可測試的,即迫使我們解除軟體中的耦合。


3、它是一種編寫文件的行為。
單元測試是一種無價的文件,它是展示函式或類如何使用的最佳文件。這份文件是可編譯、可執行的,並且它保持最新,永遠與程式碼同步。


4、它具有迴歸性。
自動化的單元測試避免了程式碼出現迴歸,編寫完成之後,可以隨時隨地的快速執行測試。


如何更好的進行單元測試?


在討論如何更好的進行單元測試之前,先來看看我們以前是怎麼測試程式碼的。

以前是這樣測試程式的:

 

    public int add(int x,int y) {
        return x + y;
    }
        
    public static void main(String args[]) {
        int z = new Junit().add(2, 3);
        System.out.println(z);
    }

 

 

如上面所示,在測試我們寫好的一個方法時,通常是用一個main方法呼叫一下我們要測試的方法,然後將結果列印一下。現在看來這種方式已經非常out了,所以出現了很多單元測試的工具,如:JUnit、TestNG等。藉助它們可以讓我們的單元測試變得非常方便、高效。今天就說說如何利用JUnit進行單元測試。


我們新建一個Java Project以便進行演示,至於Java Project怎麼建立我就不在此贅述了,如果連怎麼建Java Project,那你還不適合看這篇文章。建好以後在該專案的“src”目錄上右擊,選擇new——》JUnit Test Case,然後按下圖填寫必要資訊:



填寫好包名和類名(選擇New JUnit 4 Test),點選最下面的那個“Browse”按鈕來選擇需要測試的類:



手動輸入我們要測試的類,選擇該類,點選“OK”,回到第一張圖的介面,然後點選“Next”,來到下圖:



勾選要測試的方法,點選“Finish”,這樣我們的JUnit測試例項就建好了。然後就可以寫具體的測試了:

 


package com.tgb.junit.test;

//靜態引入
import static org.junit.Assert.*;
import static org.hamcrest.Matchers.*;

import org.junit.Test;

import com.tgb.junit.Junit;

public class JUnitTest {

    @Test
    public void testAdd() {
        int z = new  Junit().add(2, 3);
        assertThat(z , is(5));
    }

    @Test
    public void testDivide() {
        int z = new Junit().divide(4, 2);        
        assertThat(z, is(2));
    }
}

 



寫好以後,右擊該類選擇“Run As”——》“JUnit Test”,出現下圖代表測試通過:

 



到這裡,可能有人會有疑問,JUnit跟用main方法測試有什麼區別呢?

首先,JUnit的結果更加直觀,直接根據狀態條的顏色即可判斷測試是否通過,而用main方法你需要去檢查他的輸出結果,然後跟自己的期望結果進行對比,才能知道是否測試通過。有一句話能夠很直觀的說明這一點——keeps the bar green to keeps the code clean。意思就是說,只要狀態條是綠色的,那麼你的程式碼就是正確的。

第二點,JUnit讓我們同時執行多個測試變得非常方便,下面就演示一下如何進行多例項測試:

首先我們要再建一個待測試類,然後再建一個對應的JUnit測試例項,步驟略。然後在我們測試例項的包上右擊選擇“Run As”——》“Run Configurations”,如下圖;



選擇第二項“Run all tests in the selected project, package or source folder”,然後點選“Run”效果如下:



可以看到,我們本次測試了兩個類,共三個方法,這種方便的效果在測試例項越多的情況下,體現的越明顯。至於main方法執行多個測試,想想就覺得非常麻煩,這裡就不演示了。


JUnit除了可以測試這些簡單的小程式,還可以測試Struts、JDBC等等,這裡只是用這個小程式做過簡單的介紹。本例項使用的是hamcrest斷言,而沒有使用老的斷言,因為hamcrest斷言更加接近自然語言的表達方式,更易於理解。


本例項需要引入以下三個jar包:

hamcrest-core-1.3.jar
hamcrest-library-1.3.jar
junit-4.10.jar


最後附上常用hamcrest斷言的使用說明:

數值型別
//n大於1並且小於15,則測試通過
assertThat( n, allOf( greaterThan(1), lessThan(15) ) );
//n大於16或小於8,則測試通過
assertThat( n, anyOf( greaterThan(16), lessThan(8) ) );
//n為任何值,都測試通過
assertThat( n, anything() );
//d與3.0的差在±0.3之間,則測試通過
assertThat( d, closeTo( 3.0, 0.3 ) );
//d大於等於5.0,則測試通過
assertThat( d, greaterThanOrEqualTo (5.0) );
//d小於等於16.0,則測試通過
assertThat( d, lessThanOrEqualTo (16.0) );

字元型別
//str的值為“tgb”,則測試通過
assertThat( str, is( "tgb" ) );
//str的值不是“tgb”,則測試通過
assertThat( str, not( "tgb" ) );
//str的值包含“tgb”,則測試通過
assertThat( str, containsString( "tgb" ) );
//str以“tgb”結尾,則測試通過
assertThat( str, endsWith("tgb" ) ); 
//str以“tgb”開頭,則測試通過
assertThat( str, startsWith( "tgb" ) ); 
//str忽略大小寫後,值為“tgb”,則測試通過
assertThat( str, equalToIgnoringCase( "tgb" ) ); 
//str忽略空格後,值為“tgb”,則測試通過
assertThat( str, equalToIgnoringWhiteSpace( "tgb" ) );
//n與nExpected相等,則測試通過(物件之間)
assertThat( n, equalTo( nExpected ) ); 

collection型別
//map中包含key和value為“tgb”的鍵值對,則測試通過
assertThat( map, hasEntry( "tgb", "tgb" ) );
//list中包含“tgb”元素,則測試通過
assertThat( iterable, hasItem ( "tgb" ) );
//map中包含key為“tgb”的元素,則測試通過
assertThat( map, hasKey ( "tgb" ) );
//map中包含value為“tgb”的元素,則測試通過
assertThat( map, hasValue ( "tgb" ) );

 

 

相關文章