Spring Boot + MockMvc 测试Controller Api接口

本文参考 SpringBoot junit 测试 controller (MockMvc)Spring Boot干货系列:(十二)Spring Boot使用单元测试

MockMvc是什么

MockMvc是Spring Test提供的功能,可是实现对Controller层(API)做测试,也就是不必启动工程就能测试Controller接口。 
MockMvc实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,这样可以使得测试速度快、不依赖网络环境。而且提供了一套验证的工具,这样可以使得请求的验证统一而且很方便。

MockMvc在RESTful中的参数问题

使用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()输出整个响应结果信息

posted on 2020-07-17 11:26  dreamstar  阅读(1208)  评论(0编辑  收藏  举报