JMockit工具總結


JMockit is a Java toolkit for automated developer testing.It contains APIs for the creation of the objects to be tested, for mocking dependencies, and for faking externalAPIs; JUnit (4 and 5) and TestNG test runners are supported.It also contains an advanced code coverage tool.

 

Jmockit是一個Java工具,用於開發者做自動測試。Jmockit包含了被創建對象的創建API,主要是為了模擬外部依賴和外部API,支持Junit4、5和TestNG,並且Jmockit還包含了優秀的代碼覆蓋工具。

 

 JMockit簡介

 

JMockit是一個用於在測試階段模擬Java對象的Java框架,支持Junit4和TestNG。JMockit使用Java的instrumentation API在運行時修改類class文件的字節碼來動態的改變類的行為。JMockit比較強的地方在於它的可表達性和開箱即用的能力,它支持模擬靜態方法和私有方法(不推薦mock私有方法)。

 

Jmockit具有超強的表達能力。我們只需要創建mocks並定義其行為,我們不需要進行各種鏈式調用,只要直接定義它們就好。也就是說你不會有如下這樣的操作。

而是直接定義mock的行為即可。

 

 

可能看起來代碼變多了,但是你完全可以將它們寫在一行。重點在於,我們不需要在寫冗長的鏈式調用代碼了。你只需要定義你想mock對象方法調用時有什么行為即可。另外result=value部分,你可以完全返回任何你想要的值(固定值、動態生成的值、異常等等),可以看到JMockit有極強的表達力。

 

 

JMockit的Record-Replay-Verify模型

 

使用JMockit進行測試分為三個不同的階段:錄制、重放和核實。

1.  錄制階段,我們為下一步所需要用到的測試都定義默認的行為。

2. 重放階段,也就是真正執行測試代碼的階段,之前定義的模擬方法,構造器等等都會在這個階段播放。

3. 最后,在核實階段,我們將對測試的結果進行斷言,來確認和我們的預期是一致的。

 

 

我們通過一個簡單的例子來了解下JMockit的精髓吧。

 

 

 

在上面的例子中,通過參數Mock了一個對象,定義了兩個Expectations, 一個Verification。整個流程讀下來就是,我希望我Mock的對象的sum(1,2)返回3,sum(2,3)返回5,然后開始使用Mock的對象來執行代碼;接下來確認Mock對象的sum(int,int)方法被調用了2次;最后使用兩個斷言來看程序執行結果是否符合自己的預期。

 

Mock對象的創建

 

當我們使用JMockit時,最簡單的創建mocks的方法就是使用注解了。這里有3個注解來創建mocks, @Mocked、@Injectable、@Capturing。

當我們使用@Mocked注解來標注一個成員變量,它將會為每個該類的實例對象創建一個mocked實例,即使你new出來的實例也會受到影響。但是,使用@Injectable注解來標注一個成員變量,只會對標注的成員變量實例進行模擬,其他實例不受影響,你new出來的對象仍然保持原有行為。

我們通過一個簡單的例子來理解下。

 

 

但是如果我們將@Mocked換成@Injectable, 我們得到的結果將會是下面這樣。

 

@Capturing注解行為和@Mocked一樣,但是會為被標注變量所屬類的子類或實現類進行模擬,也就是上述TestCalculator的子類的sum(1,2)也會返回4。

@Tested注解常常和@Injectable注解一起使用,@Tested用來表示要測試的對象,@Injectable一般用來模擬主業務中其他的依賴的對象。

比如現在有一個業務,用戶上傳頭像的業務,涉及FileService和UserService兩個類的操作,但是我們現在無法搭建文件服務,所以我們決定模擬文件服務,我們通過代碼來看一下。

 

 

上述代碼中的主要測試點是UserService實例的saveLogoKey()方法,因此我們用@Tested來標注UserService,但是我們又缺少FileService的環境,所以我們用@Injectable來標注FileService,並使用Expectations來模擬其行為,使其返回一個fake file unique key, 那么userService就可以走通了。

 

Expectations & Verifications

 

接下來的方法將用到Expectations和Verifications。

 

any通配參數

Jmockit提供了一系列的通用字段:anyInt、anyString等等。以此來讓參數的匹配更加通用,這些通用字段都是以any開頭的。比如我們想給一個mock對象的f(String s)方法接受任何參數都返回true,我們就可以在Expectations中使用通用字段。

注:在使用Expectations時,里面定義的方法期望必須在Expectations下面的代碼段有調用,要不然會報錯Missing Invocation。

注:當使用Any工具字段的時候,我們必須要將參數強轉到方法所接受的類型,如上面代碼所示。



with通配方法

JMockit還提供了很多通用方法去處理通用參數匹配問題,這些方法都以With開頭(withSubString(subString)、withNotEqual(1)),這些方法比any開頭的字段更加高級,我們可以看下面這個例。

 

上面的例子中使用了withEqual(1)和withNotEqual(2),表示calculator在sum()的第一個參數為1時、第二個參數不為2時,返回結果是4。

 

null is NOT null

null是一個定義任意引用對象的語法糖,如果你想驗證當前方法接受的參數是null的引用,我們可以使用withNull()。

下面的例子,我們將定義mock對象的行為,這個行為將會被觸發,如果傳入的參數是String、List和null的引用。

可以注意到區別:null意味着任何list,withNull()意味着null的list的引用。特別是,為了避免將值強轉到聲明的參數類型時。

這個的唯一使用場景就是,至少有一個詳細的參數匹配器被用到Expections中(要么是Any要么是With)。

 

times限制模擬對象調用次數

有時候,我們需要限制mock方法的調用次數。JMockit使用times、minTimes和maxTimes來達成目的。我們通過一個小例子來體驗一下。

上面的例子在Expectations使用了times=2來期望方法會被調用2次,如果不夠2次或超過2次都將產生錯誤。

 

自定義通用類型

JMockit還允許自定義通用類型,使用withArgThat和BaseMatcher來實現。

 

 

Results和Returns

JMockit使用Result和Returns來模擬mock對象的返回值,Result和Returns可以覆蓋90%的返回值類型,我們通過一個例子來了解下。

注: Returning只能用在Expectations中。

 

JMockit還支持第三種方式來返回值。

 

 

上述例子使用代理來返回值,如果傳遞的參數<3, 則返回5, 否則拋出異常。

 

JMockit高級方案

 

JMockit除了提供了上述的Expectations和Verifications等特性之外,還提供了其他的高級特性。

•   Faking(MockUp API)

•   Deencapsulation功能類

•   如何使用一個mock來模擬多個接口

•  如何重用Expectations和Verifications

在原先JMockit版本中,支持對私有變量對的mock, 但是在我測試的1.43版本中,不再支持對private字段和方法進行模擬,因為對於私有方法和內部類的測試往往是不被推薦的。

 

MockUpAPI

 

除了可以使用Expectations和Verifications的特性,我們還可以使用MockUp類來進行字段、方法的模擬(靜態方法和靜態變量不推薦使用MockUp),並且MockUp貌似只能模擬類,不能模擬接口。

 

可以看到,上述方法沒有對max方法進行模擬,則會導致調用方法時出現actual=0的情況。

 

Deencapsulation

 

接下來,我們使用Deencapsulation來模擬公有字段。

 

如何在一個測試類中模擬多個接口

假設我們現在想測試一個類,但是還沒有實現,但是我們很清楚的知道它將會實現多個接口。我們可以使用泛型和定義一個類來實現那多個接口。

我們將通過下面的例子來看看如何在一個測試類下模擬多個接口。

 

總結

 

JMockit為我們單元測試引入了模擬對象方案,有了JMockit我們基本上可以對任何類、接口、方法、字段進行模擬,來隔離外部依賴,從而寫出清晰易讀的測試代碼。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM