本文參考 SpringBoot junit 測試 controller (MockMvc)、Spring Boot干貨系列:(十二)Spring Boot使用單元測試
MockMvc是什么
MockMvc是Spring Test提供的功能,可是實現對Controller層(API)做測試,也就是不必啟動工程就能測試Controller接口。
MockMvc實現了對Http請求的模擬,能夠直接使用網絡的形式,轉換到Controller的調用,這樣可以使得測試速度快、不依賴網絡環境。而且提供了一套驗證的工具,這樣可以使得請求的驗證統一而且很方便。
使用Spring Boot + MockMVC 測試Spring MVC請求的步驟:
1.准備測試環境
2.通過MockMvc執行請求,添加驗證斷言 ,添加結果處理器,得到MvcResult進行自定義斷言/進行下一步的異步請求
3.卸載測試環境
有以下controller需要測試
package com.example.junittestdemo;
import java.io.IOException;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.fasterxml.jackson.core.format.InputAccessor.Std;
@RestController
@RequestMapping("/student")
public class StudentController {
@Autowired
private StudentService studentService;
@GetMapping("/findAll")
public ResponseEntity findAll() throws IOException {
List<Student> students = studentService.findAll();
Student student = new Student();
student.setName("xxx");
students.add(student);
return ResponseEntity.ok(students);
}
@PostMapping(value = "/uploadFile")
public ResponseEntity uploadFile(@RequestBody String file) throws IOException {
studentService.uploadFile(file);
return ResponseEntity.ok().build();
}
}
1.准備測試環境---引入起步依賴
<!-- 測試web 請求,所以要添加spring web起步依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MockMvc 是Spring Test 提供的功能, 需要添加spring test的依賴jar包 -->
<!-- 在Spring Boot Test中,實現了MockMvc的自動配置,使得我們可以通過@AutoConfigureMockMvc注解開啟MockMvc的配置.直接通過@Autowired注入MockMvc使用。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mockito/mockito-all -->
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>2.0.2-beta</version>
<scope>test</scope>
</dependency>
不能引入spring-boot-starter-security起步依賴,否則運行測試時會報錯Full authentication is required to access this resource參考 SpringBoot框架報錯Full authentication is required to access this resource
2.測試類 ---通過MockMvc執行請求,添加驗證斷言 ,添加結果處理器,得到MvcResult進行自定義斷言/進行下一步的異步請求
package com.example.junittestdemo;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@EnableWebMvc
@AutoConfigureMockMvc
@SpringBootTest(classes = StudentController.class)
public class StudentControllerTest {
@Autowired
private MockMvc mockMvc;
@MockBean
private StudentService studentService;
@Test
public void testFindAll() throws Exception {
// 執行一個get請求
mockMvc.perform(MockMvcRequestBuilders.get("/student/findAll"))
// 添加斷言
.andExpect(MockMvcResultMatchers.status().isOk())
// 添加返回結果 一般在測試時候用
.andDo(MockMvcResultHandlers.print());
// 驗證方法執行過一次
verify(studentService, times(1)).findAll();
}
@Test
public void uploadFileTest() throws Exception {
String file = "test.xlsx";
// 執行一個post請求
mockMvc.perform(MockMvcRequestBuilders.post("/student/uploadFile")
// post請求的內容
.content(file)
// post請求數據類型
.contentType(MediaType.APPLICATION_JSON_VALUE))
// 添加斷言
.andExpect(MockMvcResultMatchers.status().isOk())
// 添加返回結果
.andDo(MockMvcResultHandlers.print());
// 驗證方法執行過一次
verify(studentService, times(1)).uploadFile(file);
}
}
注解解釋:
@SpringBootTest注解:是SpringBoot自1.4.0版本開始引入的一個用於測試的注解,來提供SpringBoot單元測試環境支持。
SpringBoot單元測試環境支持 就是說 可以取到spring中的容器的實例,如果配置了@Autowired那么就自動將對象注入。如果你使用的JUnit版本如果是JUnit 4不要忘記在測試類上添加@RunWith(SpringJUnit4ClassRunner.class),JUnit 5就不需要了。
- 注:這是SpringBoot Test的功能 import org.springframework.boot.test.context.SpringBootTest;
@RunWith(SpringJUnit4ClassRunner.class),讓測試運行於Spring測試環境,以便在測試開始的時候自動創建Spring的應用上下文
- import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; - Spring Boot 2.2之后 ,也就是junit5中 啟動Spring Boot 測試環境 需要@SpringBootTest 一個注解就好。
- Spring Boot 2.2之前 ,也就是junit4中 啟動 @RunWith(SpringJUnit4ClassRunner.class) 和 @SpringBootTest 兩個注解一塊使用。否則@Autowired注入的會是null 參考解決SpringBoot單元測試@Autowired不生效問題
@EnableWebMvc注解:為該應用添加SpringMVC的功能,即添加之后可以在項目中,可以使用@RequestMapping等注解來定義請求處理與請求uri的映射和其他SpringMvc提供的功能
- 注:這是spring web的功能 import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@AutoConfigureMockMvc注解 :表示 MockMvc交給Spring容器管理,開啟自動配置MockMvc 。我們需要使用時 只要注入就可以了。如果沒有這個注解,需要自己根據應用上下文創建 管理MockMvc對象。有了這個注解,只要注入MockMvc就可以使用了。
- 注:這是Spring test的功能 import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
@Test注解 在junit5中 是 import org.junit.jupiter.api.Test 而不是import org.junit.Test;
MockMvc解釋: 執行請求 並返回ResultActions實例,添加斷言等
mockMvc.perform執行一個請求,會自動執行SpringMVC的流程並映射到相應的控制器執行處理,返回一個ResultActions實例
MockMvcRequestBuilders.get("/student/findAll") 根據uri模板和uri變量值 構造一個GET,PUT,POST,DELETE等請求,Post請求就用.post方法
contentType(MediaType.APPLICATION_JSON_UTF8)代表發送端發送的數據格式是application/json;charset=UTF-8
accept(MediaType.APPLICATION_JSON_UTF8)代表客戶端希望接受的數據類型為application/json;charset=UTF-8
ResultActions.andExpect添加執行完成后的斷言
ResultActions.andExpect(MockMvcResultMatchers.status().isOk())方法看請求的狀態響應碼是否為200如果不是則拋異常,測試不通過
ResultActions.andExpect(MockMvcResultMatchers.jsonPath(“$.author”).value(“嘟嘟MD獨立博客”))這里jsonPath用來獲取author字段比對是否為嘟嘟MD獨立博客,不是就測試不通過
ResultActions.andDo添加一個結果處理器,表示要對結果做點什么事情,比如此處使用MockMvcResultHandlers.print()輸出整個響應結果信息
