今天聊聊如何在 SpringBoot 中集成 Junit5、MockMvc、Mocktio。Junit5 是在 Java 棧中應用最廣的測試框架,Junit4 一度霸榜。
升級到 Junit5 之后,除了增加 Java8 的很多特性,做了很多功能增強,在結構上做了優化調整,拆分了很多不同的模塊,可以按需引入,比如:
- JUnit Platform - 在 JVM 上啟動測試框架
- JUnit Jupiter - 在 JUnit5 中編寫測試和擴展
- JUnit Vintage - 提供運行基于 JUnit3 和 JUnit4 的測試引擎
從 SpringBoot 2.2.0 之后,Junit5 已經成為了默認的 Junit 版本。有了 JUnit Vintage,從 Junit4 遷移到 Junit5 的成本極低。所以本文就直接針對 Junit5 開始了。
版本
先說版本,是為了避免因為版本差異出現各種奇怪的問題:
- JDK:jdk8(小版本可以忽略)
-
SpringBoot:2.5.2
- 繼承spring-boot-starter-parent
- 依賴spring-boot-starter-web
- 依賴spring-boot-starter-test
- JUnit:5.7.2
- Mockito:3.9.0
- hamcrest:2.2
SpringBoot 的好處在于,只要繼承spring-boot-starter-parent或引入spring-boot-pom-dependencies,然后添加spring-boot-starter-test依賴即可。定義的 POM 內容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
<? xml version = "1.0" encoding = "UTF-8" ?> < project xmlns = "http://maven.apache.org/POM/4.0.0" xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion >4.0.0</ modelVersion > < parent > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-parent</ artifactId > < version >2.5.2</ version > </ parent > < groupId >cn.howardliu.effective.spring</ groupId > < artifactId >springboot-junit5-mockito</ artifactId > < version >0.0.1-SNAPSHOT</ version > < name >springboot-junit5-mockio</ name > < dependencies > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-web</ artifactId > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-devtools</ artifactId > < scope >runtime</ scope > < optional >true</ optional > </ dependency > < dependency > < groupId >org.projectlombok</ groupId > < artifactId >lombok</ artifactId > < optional >true</ optional > </ dependency > < dependency > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-starter-test</ artifactId > < scope >test</ scope > </ dependency > </ dependencies > < build > < plugins > < plugin > < groupId >org.springframework.boot</ groupId > < artifactId >spring-boot-maven-plugin</ artifactId > </ plugin > </ plugins > </ build > </ project > |
因為繼承了spring-boot-starter-parent,所以我們依賴的spring-boot-starter-test不需要寫具體的版本,可以直接集成父級的版本定義。其中,spring-boot-starter-web是用于提供 REST API 的 web 容器,spring-boot-starter-test可以提供各種測試框架的,spring-boot-maven-plugin是將 SpringBoot 應用打包為可執行 jar 的插件。
項目結構
因為是 DEMO 示例,我們實現一個 Echo 接口,能夠接收請求參數,并返回加工后的字符串。按照慣例,我們使用萬能的Hello, World!。
我們的項目結構如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
├── pom.xml └── src ├── main │ ├── java │ │ └── cn │ │ └── howardliu │ │ └── effective │ │ └── spring │ │ └── springbootjunit5mockio │ │ ├── SpringbootJunit5MockioApplication.java │ │ ├── controller │ │ │ └── EchoController.java │ │ └── service │ │ ├── EchoService.java │ │ └── impl │ │ └── EchoServiceImpl.java │ └── resources │ └── application.yaml └── test └── java └── cn └── howardliu └── effective └── spring └── springbootjunit5mockio └── controller ├── EchoControllerMockTest.java └── EchoControllerNoMockitoTest.java |
- SpringbootJunit5MockioApplication:SpringBoot 應用啟動入口
- EchoController:接口定義
- EchoService:實現業務邏輯接口
- EchoServiceImpl:接口實現
- EchoControllerMockTest:使用 Mock 代理 EchoService 實現
- EchoControllerNoMockitoTest:直接測試接口實現
EchoServiceImpl
我們看下EchoService的實現,這將是我們 DEMO 的核心實現:
1
2
3
4
5
6
7
|
@Service public class EchoServiceImpl implements EchoService { @Override public String echo(String foo) { return "Hello, " + foo; } } |
EchoControllerNoMockitoTest
我們先使用 Junit5+MockMvc 實現 Controller 接口的普通調用,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@SpringBootTest (classes = SpringbootJunit5MockioApplication. class ) @AutoConfigureMockMvc class EchoControllerNoMockitoTest { @Autowired private MockMvc mockMvc; @Test void echo() throws Exception { final String result = mockMvc.perform( MockMvcRequestBuilders.get( "/echo/" ) .param( "name" , "看山" ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn() .getResponse() .getContentAsString(StandardCharsets.UTF_8); Assertions.assertEquals( "Hello, 看山" , result); } } |
我們通過SpringBootTest注解定義這是一個 SpringBoot 應用的測試用例,然后通過AutoConfigureMockMvc啟動測試容器。這樣,就可以直接注入MockMvc實例測試 Controller 接口。
這里需要注意一點,網上很多教程會讓寫@ExtendWith({SpringExtension.class})這樣一個注解,其實完全沒有必要。通過源碼我們可以知道,SpringBootTest注解已經添加了ExtendWith。
EchoControllerMockTest
這個測試用例中,我們通過 Mockito 組件代理EchoService的echo方法,代碼如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
@SpringBootTest (classes = SpringbootJunit5MockioApplication. class ) @ExtendWith (MockitoExtension. class ) @AutoConfigureMockMvc class EchoControllerMockTest { @Autowired private MockMvc mockMvc; @MockBean private EchoService echoService; @BeforeEach void setUp() { Mockito.when(echoService.echo(Mockito.any())) .thenReturn( "看山說:" + System.currentTimeMillis()); } @Test void echo() throws Exception { final String result = mockMvc.perform( MockMvcRequestBuilders.get( "/echo/" ) .param( "name" , "看山的小屋" ) ) .andExpect(MockMvcResultMatchers.status().isOk()) .andDo(MockMvcResultHandlers.print()) .andReturn() .getResponse() .getContentAsString(StandardCharsets.UTF_8); Assertions.assertTrue(result.startsWith( "看山" )); } } |
在這個示例中,我們需要注意@ExtendWith(MockitoExtension.class)注解,這個注解是用于引入MockBean的,我們通過對echo方法的攔截,使其返回我們定義好的響應結果。這種方式是為了在多系統或者多功能測試時,不需要真正調用接口。
比如,我們需要獲取用戶手機號,通常在接口中會校驗用戶有沒有登錄,我們就可以使用 Mockito 的能力代理登錄驗證,使結果永遠是 true。
到此這篇關于SpringBoot+JUnit5+MockMvc+Mockito單元測試的實現的文章就介紹到這了,更多相關SpringBoot JUnit5 MockMvc Mockito單元測試內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!
原文鏈接:https://blog.csdn.net/liuxinghao/article/details/120244720