測試在軟體生命週期中的重要性,不用我多說想必大家也都非常清楚。軟體測試有很多分類,從測試的方法上可分為:黑盒測試、白盒測試、靜態測試、動態測試等;從軟體開發的過程分為:單元測試、整合測試、確認測試、驗收、迴歸等。
在眾多的分類中,與開發人員關係最緊密的莫過於單元測試了。像其他種類的測試基本上都是由專門的測試人員來完成,只有單元測試是完全由開發人員來完成的。那麼今天我們就來說說什麼是單元測試,為什麼要進行單元測試,以及如更好的何進行單元測試。
什麼是單元測試?
單元測試(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" ) );