Junit Mockito實(shí)現(xiàn)單元測(cè)試方法介紹
一、前言
相信做過開發(fā)的同學(xué),都多多少少寫過下面的代碼,很長(zhǎng)一段時(shí)間我一直以為這就是單元測(cè)試...
@SpringBootTest @RunWith(SpringRunner.class) public class UnitTest1 { @Autowired private UnitService unitService; @Test public void test() { System.out.println("----------------------"); System.out.println(unitService.sayHello()); System.out.println("----------------------"); } }
但這是單元測(cè)試嘛?unitService 中可能還依賴了 Dao 的操作;如果是微服務(wù),可能還要起注冊(cè)中心。那么這個(gè)“單元”也太大了吧!如果把它稱為集成測(cè)試,可能更恰當(dāng)一點(diǎn),那么有沒有可能最小粒度進(jìn)行單元測(cè)試嘛?
單元測(cè)試應(yīng)該是一個(gè)帶有隔離性的功能測(cè)試。在單元測(cè)試中,應(yīng)盡量避免其他類或系統(tǒng)的副作用影響。
單元測(cè)試的目標(biāo)是一小段代碼,例如方法或類。方法或類的外部依賴關(guān)系應(yīng)從單元測(cè)試中移除,而改為測(cè)試框架創(chuàng)建的 mock 對(duì)象來替換依賴對(duì)象。
單元測(cè)試一般由開發(fā)人員編寫,通過驗(yàn)證或斷言目標(biāo)的一些行為或狀態(tài)來達(dá)到測(cè)試的目的。
二、JUnit 框架
JUnit 是一個(gè)測(cè)試框架,它使用注解來標(biāo)識(shí)測(cè)試方法。JUnit 是 Github 上托管的一個(gè)開源項(xiàng)目。
一個(gè) JUnit 測(cè)試指的是一個(gè)包含在測(cè)試類中的方法,要定義某個(gè)方法為測(cè)試方法,請(qǐng)使用 @Test 注解標(biāo)注該方法。該方法執(zhí)行被測(cè)代碼,可以使用 JUnit 或另一個(gè) Assert 框架提供的 assert 方法來檢查預(yù)期結(jié)果與實(shí)際結(jié)果是否一致,這些方法調(diào)用通常稱為斷言或斷言語句。
public class UnitTest2 { @Test public void test() { String sayHello = "Hello World"; Assert.assertEquals("Hello World", sayHello); } }
以下是一些常用的 JUnit 注解:
以下是一些常用的 Assert 斷言:
三、Mockito 框架
從上面的介紹我們可以認(rèn)識(shí)到,如何減少對(duì)外部的依賴才是實(shí)踐單元測(cè)試的關(guān)鍵。而這正是Mockito的使命,Mockito 是一個(gè)流行的 mock 框架,可以與 JUnit 結(jié)合使用,Mockito 允許我們創(chuàng)建和配置 mock 對(duì)象,使用 Mockito 將大大簡(jiǎn)化了具有外部依賴項(xiàng)的類的測(cè)試開發(fā)。spring-boot-starter-test 中默認(rèn)集成了 Mockito,不需要額外引入。
在測(cè)試中使用 Mockito,通常會(huì):
- mock 外部依賴關(guān)系并將 mock 對(duì)象插入待測(cè)代碼
- 執(zhí)行被測(cè)代碼
- 驗(yàn)證代碼是否正確執(zhí)行
3.1 使用 Mockito 創(chuàng)建 mock 對(duì)象
Mockito 提供了幾種創(chuàng)建 mock 對(duì)象的方法:
- 使用靜態(tài) mock() 方法
- 使用 @Mock 注解
如果使用 @Mock 注解,則必須觸發(fā)創(chuàng)建帶有 @Mock 注解的對(duì)象。使用 MockitoRule 可以做到,它通過調(diào)用靜態(tài)方法 MockitoAnnotations.initMocks(this) 來填充帶 @Mock 注解的字段。或者可以使用 @RunWith(MockitoJUnitRunner.class)。
public class UnitTest3 { // 觸發(fā)創(chuàng)建帶有 @Mock 注解的對(duì)象 @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); // 1. 使用 @Mock 注解創(chuàng)建 mock 對(duì)象 @Mock private UnitDao unitDao; @Test public void test() { // 2. 使用靜態(tài) mock() 方法創(chuàng)建 mock 對(duì)象 Iterator iterator = mock(Iterator.class); // when...thenReturn / doReturn...when 模擬依賴調(diào)用 when(iterator.next()).thenReturn("hello"); doReturn(1).when(unitDao).delete(anyLong()); // 斷言 Assert.assertEquals("hello", iterator.next()); Assert.assertEquals(new Integer(1), unitDao.delete(1L)); } }
3.2 使用 mock 對(duì)象實(shí)踐單元測(cè)試
我們要單元測(cè)試的內(nèi)容,常常包含著對(duì)數(shù)據(jù)庫的訪問等等,那么我們要如何 mock 掉這部分調(diào)用呢?我們可以使用 @InjectMocks 注解創(chuàng)建實(shí)例并使用 mock 對(duì)象進(jìn)行依賴注入。
@Service public class UnitServiceImpl implements UnitService { @Autowired private UnitDao unitDao; @Override public String sayHello() { Integer delete = unitDao.delete(1L); System.out.println(delete); return "hello unit"; } }
@RunWith(MockitoJUnitRunner.class) public class UnitTest2 { @Mock private UnitDao unitDao; @InjectMocks private UnitServiceImpl unitService; @Test public void unitTest() { // mock 調(diào)用 when(unitDao.delete(anyLong())).thenReturn(1); Assert.assertEquals("hello unit", unitService.sayHello()); } }
Mockito 還有很多有趣的實(shí)踐,比如:@Spy或spy()方法、verify()驗(yàn)證等等,鑒于篇幅原因,讀者可自行挖掘。
3.3 使用 PowerMock mock 靜態(tài)方法。
Mockito 也有一些局限性。例如:不能 mock 靜態(tài)方法和私有方法。這個(gè)時(shí)候我們就要用到 PowerMock,PowerMock 支持 JUnit 和 TestNG,擴(kuò)展了 EasyMock 和 Mockito 框架,增加了mock static、final 方法的功能。
首先需要引入 PowerMock 的依賴:
<!-- PowerMock --> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>2.0.7</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito2</artifactId> <version>2.0.7</version> </dependency>
接下來就能愉快的 mock 靜態(tài)方法了。
@RunWith(PowerMockRunner.class) @PrepareForTest({StringUtils.class}) public class UnitTest4 { @Test public void test() { mockStatic(StringUtils.class); when(StringUtils.getFilename(anyString())).thenReturn("localhost"); Assert.assertEquals("localhost", StringUtils.getFilename("")); } }
到此這篇關(guān)于Junit Mockito實(shí)現(xiàn)單元測(cè)試方法介紹的文章就介紹到這了,更多相關(guān)Junit Mockito單元測(cè)試內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot 攔截器和自定義注解判斷請(qǐng)求是否合法
這篇文章主要介紹了SpringBoot 攔截器和自定義注解判斷請(qǐng)求是否合法,幫助大家更好的理解和使用springboot框架,感興趣的朋友可以了解下2020-12-12Java任務(wù)調(diào)度的常見實(shí)現(xiàn)方法與比較詳解
這篇文章主要介紹了Java任務(wù)調(diào)度的常見實(shí)現(xiàn)方法與比較,結(jié)合實(shí)例形式分析了Java任務(wù)調(diào)度的四種常見實(shí)現(xiàn)方法,使用區(qū)別及相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-08-08SpringDataJpa創(chuàng)建聯(lián)合索引的實(shí)現(xiàn)
這篇文章主要介紹了SpringDataJpa創(chuàng)建聯(lián)合索引的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12基于parameters參數(shù)實(shí)現(xiàn)參數(shù)化過程解析
這篇文章主要介紹了基于parameters參數(shù)實(shí)現(xiàn)參數(shù)化過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-08-08復(fù)雜JSON字符串轉(zhuǎn)換為Java嵌套對(duì)象的實(shí)現(xiàn)
這篇文章主要介紹了復(fù)雜JSON字符串轉(zhuǎn)換為Java嵌套對(duì)象的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09