Junit Mockito實現單元測試方法介紹
一、前言
相信做過開發的同學,都多多少少寫過下面的代碼,很長一段時間我一直以為這就是單元測試…
@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("----------------------"); } }
但這是單元測試嘛?unitService 中可能還依賴瞭 Dao 的操作;如果是微服務,可能還要起註冊中心。那麼這個“單元”也太大瞭吧!如果把它稱為集成測試,可能更恰當一點,那麼有沒有可能最小粒度進行單元測試嘛?
單元測試應該是一個帶有隔離性的功能測試。在單元測試中,應盡量避免其他類或系統的副作用影響。
單元測試的目標是一小段代碼,例如方法或類。方法或類的外部依賴關系應從單元測試中移除,而改為測試框架創建的 mock 對象來替換依賴對象。
單元測試一般由開發人員編寫,通過驗證或斷言目標的一些行為或狀態來達到測試的目的。
二、JUnit 框架
JUnit 是一個測試框架,它使用註解來標識測試方法。JUnit 是 Github 上托管的一個開源項目。
一個 JUnit 測試指的是一個包含在測試類中的方法,要定義某個方法為測試方法,請使用 @Test 註解標註該方法。該方法執行被測代碼,可以使用 JUnit 或另一個 Assert 框架提供的 assert 方法來檢查預期結果與實際結果是否一致,這些方法調用通常稱為斷言或斷言語句。
public class UnitTest2 { @Test public void test() { String sayHello = "Hello World"; Assert.assertEquals("Hello World", sayHello); } }
以下是一些常用的 JUnit 註解:
以下是一些常用的 Assert 斷言:
三、Mockito 框架
從上面的介紹我們可以認識到,如何減少對外部的依賴才是實踐單元測試的關鍵。而這正是Mockito的使命,Mockito 是一個流行的 mock 框架,可以與 JUnit 結合使用,Mockito 允許我們創建和配置 mock 對象,使用 Mockito 將大大簡化瞭具有外部依賴項的類的測試開發。spring-boot-starter-test 中默認集成瞭 Mockito,不需要額外引入。
在測試中使用 Mockito,通常會:
- mock 外部依賴關系並將 mock 對象插入待測代碼
- 執行被測代碼
- 驗證代碼是否正確執行
3.1 使用 Mockito 創建 mock 對象
Mockito 提供瞭幾種創建 mock 對象的方法:
- 使用靜態 mock() 方法
- 使用 @Mock 註解
如果使用 @Mock 註解,則必須觸發創建帶有 @Mock 註解的對象。使用 MockitoRule 可以做到,它通過調用靜態方法 MockitoAnnotations.initMocks(this) 來填充帶 @Mock 註解的字段。或者可以使用 @RunWith(MockitoJUnitRunner.class)。
public class UnitTest3 { // 觸發創建帶有 @Mock 註解的對象 @Rule public MockitoRule mockitoRule = MockitoJUnit.rule(); // 1. 使用 @Mock 註解創建 mock 對象 @Mock private UnitDao unitDao; @Test public void test() { // 2. 使用靜態 mock() 方法創建 mock 對象 Iterator iterator = mock(Iterator.class); // when...thenReturn / doReturn...when 模擬依賴調用 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 對象實踐單元測試
我們要單元測試的內容,常常包含著對數據庫的訪問等等,那麼我們要如何 mock 掉這部分調用呢?我們可以使用 @InjectMocks 註解創建實例並使用 mock 對象進行依賴註入。
@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 調用 when(unitDao.delete(anyLong())).thenReturn(1); Assert.assertEquals("hello unit", unitService.sayHello()); } }
Mockito 還有很多有趣的實踐,比如:@Spy或spy()方法、verify()驗證等等,鑒於篇幅原因,讀者可自行挖掘。
3.3 使用 PowerMock mock 靜態方法。
Mockito 也有一些局限性。例如:不能 mock 靜態方法和私有方法。這個時候我們就要用到 PowerMock,PowerMock 支持 JUnit 和 TestNG,擴展瞭 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 靜態方法瞭。
@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("")); } }
到此這篇關於Junit Mockito實現單元測試方法介紹的文章就介紹到這瞭,更多相關Junit Mockito單元測試內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 怎樣使用PowerMockito 測試靜態方法
- Java單元測試Powermockito和Mockito使用總結
- Spring 單元測試中如何進行 mock的實現
- 如何使用Mockito調用靜態方法和void方法
- Java單元測試Mockito的使用詳解