Spring Boot + MockMvc 测试Controller Api接口
本文参考 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()输出整个响应结果信息