天天看點

Java單元測試(Junit+Mock+代碼覆寫率)

單元測試是編寫測試代碼,用來檢測特定的、明确的、細顆粒的功能。單元測試并不一定保證程式功能是正确的,更不保證整體業務是準備的。

單元測試不僅僅用來保證目前代碼的正确性,更重要的是用來保證代碼修複、改進或重構之後的正确性。

一般來說,單元測試任務包括

接口功能測試:用來保證接口功能的正确性。

局部資料結構測試(不常用):用來保證接口中的資料結構是正确的

比如變量有無初始值

變量是否溢出

邊界條件測試

變量沒有指派(即為null)

變量是數值(或字元)

主要邊界:最小值,最大值,無窮大(對于double等)

溢出邊界(期望異常或拒絕服務):最小值-1,最大值+1

臨近邊界:最小值+1,最大值-1

變量是字元串

引用“字元變量”的邊界

空字元串

對字元串長度應用“數值變量”的邊界

變量是集合

空集合

對集合的大小應用“數值變量”的邊界

調整次序:升序、降序

變量有規律

比如對于math.sqrt,給出n^2-1,和n^2+1的邊界

所有獨立執行通路測試:保證每一條代碼,每個分支都經過測試

代碼覆寫率

語句覆寫:保證每一個語句都執行到了

判定覆寫(分支覆寫):保證每一個分支都執行到

條件覆寫:保證每一個條件都覆寫到true和false(即if、while中的條件語句)

路徑覆寫:保證每一個路徑都覆寫到

相關軟體

cobertura:語句覆寫

emma: eclipse插件eclemma

各條錯誤處理通路測試:保證每一個異常都經過測試

junit是java單元測試架構,已經在eclipse中預設安裝。目前主流的有junit3和junit4。junit3中,測試用例需要繼承<code>testcase</code> 類。junit4中,測試用例無需繼承 <code>testcase</code> 類,隻需要使用@test等注解。

如果采用預設的testsuite,則測試方法必須是 <code>public void testxxx() [throws exception] {}</code> 的形式,并且不能存在依賴關系,因為測試方法的調用順序是不可預知的。

上例執行後,控制台會輸出

從中,可以猜測到,對于每個測試方法,調用的形式是:

運作測試方法

在eclipse中,可以直接在類名或測試方法上右擊,在彈出的右擊菜單中選擇 <code>run as -&gt; junit test。</code>

在 maven 中,可以直接通過 <code>mvn test</code> 指令運作測試用例。

也可以通過java方式調用,建立一個 <code>testcase</code> 執行個體,然後重載 <code>runtest()</code> 方法,在其方法内調用測試方法(可以多個)。

更加便捷地,可以在建立 <code>testcase</code> 執行個體時直接傳入測試方法名稱,junit會自動調用此測試方法,如

junit testsuite

testsuite是測試用例套件,能夠運作過個測試方法。如果不指定testsuite,會建立一個預設的testsuite。預設testsuite會掃描目前内中的所有測試方法,然後運作。

如果不想采用預設的testsuite,則可以自定義testsuite。在testcase中,可以通過靜态方法 <code>suite()</code> 傳回自定義的suite。

允許上述方法,控制台輸出

并且隻運作了testmathpow測試方法,而沒有運作testmathmin測試方法。通過顯式指定測試方法,可以控制測試執行的順序。

也可以通過java的方式建立testsuite,然後調用 <code>testcase</code>,如:

testresult中儲存了很多測試資料,包括運作測試方法數目(runcount)等。

與junit3不同,junit4通過注解的方式來識别測試方法。目前支援的主要注解有:

<code>@beforeclass</code> 全局隻會執行一次,而且是第一個運作

<code>@before</code> 在測試方法運作之前運作

<code>@test</code> 測試方法

<code>@after</code> 在測試方法運作之後允許

<code>@afterclass</code> 全局隻會執行一次,而且是最後一個運作

<code>@ignore</code> 忽略此方法

下面舉一個樣例:

如果細心的話,會發現junit3的package是<code>junit.framework</code>,而junit4是<code>org.junit</code>。

執行此用例後,控制台會輸出

可以看到,執行次序是<code>@beforeclass -&gt; @before -&gt; @test -&gt; @after -&gt; @before -&gt; @test -&gt; @after -&gt;@afterclass</code>。<code>@ignore</code>會被忽略。

與junit3類似,可以在eclipse中運作,也可以通過 <code>mvn test</code> 指令運作。

junit3和junit4都提供了一個assert類(雖然package不同,但是大緻差不多)。assert類中定義了很多靜态方法來進行斷言。清單如下:

asserttrue(string message, boolean condition) 要求condition == true

assertfalse(string message, boolean condition) 要求condition == false

fail(string message) 必然失敗,同樣要求代碼不可達

assertequals(string message, xxx expected,xxx actual) 要求expected.equals(actual)

assertarrayequals(string message, xxx[] expecteds,xxx [] actuals) 要求expected.equalsarray(actual)

assertnotnull(string message, object object) 要求object!=null

assertnull(string message, object object) 要求object==null

assertsame(string message, object expected, object actual) 要求expected == actual

assertnotsame(string message, object unexpected,object actual) 要求expected != actual

assertthat(string reason, t actual, matcher matcher) 要求matcher.matches(actual) == true

mock和stub是兩種測試代碼功能的方法。mock測重于對功能的模拟。stub測重于對功能的測試重制。比如對于list接口,mock會直接對list進行模拟,而stub會建立一個實作了list的testlist,在其中編寫測試的代碼。

強烈建議優先選擇mock方式,因為mock方式下,模拟代碼與測試代碼放在一起,易讀性好,而且擴充性、靈活性都比stub好。

比較流行的mock有:

<a href="http://jmock.org/">jmock</a>

<a href="http://www.easymock.org/">easymock</a>

<a href="http://blog.thihy.info/post/mockito.googlecode.com">mockito</a>

<a href="http://code.google.com/p/powermock/">powermock</a>

其中easymock和mockito對于java接口使用接口代理的方式來模拟,對于java類使用繼承的方式來模拟(也即會建立一個新的class類)。mockito支援spy方式,可以對執行個體進行模拟。但它們都不能對靜态方法和final類進行模拟,powermock通過修改位元組碼來支援了此功能。

easymock把測試過程分為三步:錄制、運作測試代碼、驗證期望。

錄制過程大概就是:期望method(params)執行times次(預設一次),傳回result(可選),抛出exception異常(可選)。

驗證期望過程将會檢查方法的調用次數。

一個簡單的樣例是:

easymock還支援嚴格的檢查,要求執行的方法次序與期望的完全一緻。

這裡從官方樣例中摘錄幾個典型的:

驗證調用行為

對mock對象進行stub

比較流行的工具是emma和jacoco,ecliplse插件有eclemma。eclemma2.0之前采用的是emma,之後采用的是jacoco。這裡主要介紹一下jacoco。eclmama由于是eclipse插件,是以非常易用,就不多做介紹了。

jacoco可以嵌入到ant、maven中,也可以使用java agent技術監控任意java程式,也可以使用java api來定制功能。

jacoco會監控jvm中的調用,生成監控結果(預設儲存在jacoco.exec檔案中),然後分析此結果,配合源代碼生成覆寫率報告。需要注意的是:監控和分析這兩步,必須使用相同的class檔案,否則由于class不同,而無法定位到具體的方法,導緻覆寫率均為0%。

java report

可以使用ant、mvn或eclipse來分析jacoco.exec檔案,也可以通過api來分析。

繼續閱讀