欧美企业必备技能-Mockito
歐美企業(yè)做開發(fā)除了英語是必備技能之外,使用Mockito寫unit test(單位測試)
也是必備技能,畢業(yè)經(jīng)歷的四家外企,美企,德企,德企,瑞士企業(yè),沒有一家不寫UT的,中間在一個私企過渡了一下,呵呵,UT是什么?最近,小伙伴們在寫UT時遇到了各種問題,借此機會我對UT做一個總結,希望小伙伴們在寫UT時不要繞彎路。示例的源碼可以直接通過csdn下載也可以通過git導出:https://github.com/igdnss/mockito.git
注:這里主要是介紹Mockito的使用,所以需要有一定的junit test 的基礎,文中關于junit test 不懂的地方歡迎評論,私信,第一時間解答。
- UnitTest 介紹
- 常用標簽
- Mockito介紹
- 代碼介紹
- mock對象
- 深度mock對象
- mock方法調(diào)用
- 有返回值方法調(diào)用
- 拋出異常方法調(diào)用
- 無返回值方法調(diào)用
- 迭代方法調(diào)用
- thenAnswer處理業(yè)務邏輯
- mock對象調(diào)用真實方法
- spy 部分mock
- mock參數(shù)匹配
- isA()類型判斷
- any類型判斷
- 通配符的使用
- hamcrest 的使用
- 結束語
UnitTest 介紹
在介紹Mockito之前,強調(diào)Unit Test的幾點內(nèi)容。
其中第3天提到ut要獨立于外界資源,這看起來很奇怪,沒有外界資源ut怎么能跑起來,這就是本篇要要介紹的重點。沒有外界資源,我們需要偽造出資源,也就是業(yè)內(nèi)所說mock資源。目前可以提供mock的框架有很多,例如easymock,powermock以及本文要介紹了mockito。
常用標簽
本篇主要介紹Mockito,順便將junit test中使用在方法上的標簽也整理出來,方便后面讀代碼。
@BeforeClass
在所有類執(zhí)行之前執(zhí)行,例如設置上下文環(huán)境,共享變量等。
@Before
在當前類執(zhí)行之前執(zhí)行,例如初始化對象,變量等。
@After
在當前類執(zhí)行之后執(zhí)行。
@AfterClass
在所有類執(zhí)行之后執(zhí)行
@Test
需要測試業(yè)務邏輯
@Test(timeout=xxx)
在timeout時間范圍內(nèi)如果沒有執(zhí)行完測試邏輯,則報錯
@Test(expected=Exception.class)
設置當前的測試邏輯拋出的異常,異常類型為Exception.class
@Ignore
忽略當前的測試邏輯,不執(zhí)行
Mockito介紹
官網(wǎng): https://site.mockto.org 不太喜歡這個官網(wǎng),東西有點亂,但畢竟是官方的權威性,再亂也得硬著頭皮去看。mockito是一個測試框架,通過mock(模擬)外界資源讓測試代碼無需依賴真實環(huán)境就能跑起來,可以理解為讓測試代碼在虛擬環(huán)境中跑起來。接下來,我會將工作中常用到一些知識點全部整理出來,希望能幫助大家。依賴于自己寫的一個簡單三層架構的示例進行介紹,代碼的邏輯和環(huán)境很簡單,沒有具體的數(shù)據(jù)庫,沒有具體的業(yè)務邏輯,主要是為了介紹Mockito是如何將各個部分Mock出來并完成UT的。主要測試Controller層與Service層中的方法,有個別Mock的知識點可能沒有涉及到Demo中的方法,旨在介紹知識點。其中UnitTest和Mockito的版本分別為:4.13.2,1.10.19
注意:mockito mock的資源不能是局部的,例如局總變量,私有方法是無法mock的。
代碼介紹
Controller 層:
通過此層去調(diào)用業(yè)務層,實現(xiàn)根據(jù)id查找用戶的接口
Mapper層:
/*** 并沒有真正意義上去訪問數(shù)據(jù)庫*/ public class UserMapper {public User findById(int userId) {throw new UnsupportedOperationException();} }domain層:
public class Base { } public class Client extends Base {} public class User extends Base{String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}**service層: **
public class UserService{UserMapper userMapper;public User findById(int userId) {User user = userMapper.findById(userId);return user;}public void clear() {throw new RuntimeException();}public List<User> getGroup() {throw new RuntimeException();}public int getAge() {return 18;}public int getAgeByIdAndName(int id,String name) {return 18;}public String getName(Base base) {throw new RuntimeException();}}以上代碼真的是一位含苞待放的姑娘,一切的一切都是那么的干凈清爽,在這些的代碼基礎之上我們對mockito進行抽絲剝繭。
mock對象
三種最常用的方法。
使用此方法必須要在@RunWith(MockitoJUnitRunner.class)中傳入MockitoJUnitRunner.class 。這種法一般用于測試方法中局部對象的mock
示例
可以使用@Mock標簽,一般mock全局對象。
示例
注:mock的對象只是一個空對象,其內(nèi)部的屬性并沒有mock出來,所以直接使用mock的對象調(diào)用方法是會報空指針異常,因此使用mock的對象調(diào)用方法時,還需要mock方法的調(diào)用。或者在@Before中加上MockitoAnnotaion.initMocks(this);
深度mock對象
FindingController getUser()方法中調(diào)用了UserService的getUser()返回結果為User,如果這需要測試user.getName(),就得再需要mock一個User 對象??梢允褂蒙疃萴ock來解決這個問題。
@Mock(answer=Answers.RETURNS_DEEP_STUBS)//深度mockprivate UserService userService;mock方法調(diào)用
有返回值方法調(diào)用
語法一: when(T methodCall).thenReturn(T returnValue);
methodCall:方法調(diào)用;returnValue:調(diào)用此方法mock出的返回值。注:如果對象是mock出來的,必須要mock它的方法調(diào)用,否則會報空指針異常,因為mock的時候只mock一個空對象,其內(nèi)部的屬性并沒有mock出來,所以報空指針異常。
語法二: doReturn(Object toBeReturned).when(T mock).方法 。
示例:
一步到位,無需多次mock
拋出異常方法調(diào)用
語法一: when(T methodCall).thenThrow(Class<? extends Throwable>… throwableClasses);這種方法已經(jīng)被derecated了,基本不用。
語法二: doThrow(Class<? extends Throwable> toBeThrown).when(T mock).方法;
示例:
無返回值方法調(diào)用
語法: doNothing().when(T mock).方法; 調(diào)用完方法后需要驗證此方法是被調(diào)用的次數(shù)。verify(T mock, VerificationMode mode).方法。其中mode表示方法被調(diào)用的次數(shù),可以不傳,默認為times(1)。
示例:
迭代方法調(diào)用
語法一: when(T methodCall).thenReturn(Object value,Object … values);
語法二: when(T methodCall).thenReturn(Object value,Object … values);
針對同一個方法,希望每一次的調(diào)用結果不同,就應該用到此方法
示例:
thenAnswer處理業(yè)務邏輯
語法: when(T methodCall).thenAnswer(Answer<?> answer)
當有一些結果為動態(tài)結果時,就要用這種方式了。
示例:
mock對象調(diào)用真實方法
語法: when(T methodCall).thenCallRealMethod();
使用mock對象調(diào)用真實的方法就需要使用到此種方式。注意:這里調(diào)用的方法不能是抽象方法
示例:
spy 部分mock
語法: Object o = spy(真實對象);
在有些測試場景下,需要測試真實對象的值,對部分只能使用mock來處理,可以借助spy來完成。
示例:
mock參數(shù)匹配
在前面的示例中提到參數(shù)匹配,就是當調(diào)用一個方法時,應該返回什么樣的值。這里主要介紹一下以下幾種方式。
isA()類型判斷
示例:
測試getName()中傳入的是否為Base類型的對象
any類型判斷
這個方法我基本沒有用過,感覺意義不大
示例:
通配符的使用
前文中使用過通配符anyInt(), Mockito中提供了好幾個通配符,這里舉兩個例子。使用通配符的時候一定要注意,參數(shù)列表中一處使用通配符,就得處處使用通配符,如果想傳入特定的值一定要使用eq()方法。通配符的優(yōu)先級大于eq(),如果同樣的方法多個mock,通配符寫在最后一句的話會覆蓋前面mock的結果。
示例:
hamcrest 的使用
hamcrest中提供了很多強大的功能,配合assertThat()使用會增加代碼的可讀性,代碼編寫風格符合陳述式風格。另外,可以不用使用assertTure(), assertEquals()等斷言方法,使用一個assertThat()就可以了。以下示例獨立于文章開頭的業(yè)務代碼。但assertThat已經(jīng)deprecated了,不知道為什么。
示例:
結束語
終于寫完了,真心不容易,不過挺開心。Mockito中常用點都在這里了,當然Mockito中還有很多知識點,大家可以參考官網(wǎng)。希望本文能幫助大家,祝大家在IT之路上少走彎路,一路綠燈不堵車,測試一性通過,bug秒解!
總結
以上是生活随笔為你收集整理的欧美企业必备技能-Mockito的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: kafka消费端Attempt to h
- 下一篇: 什么是中间件?如何设计一个中间件?