SpringBoot集成MockMvc测试接口
1、简介
使用模拟对象,可以模拟复杂的、真实的对象行为。如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。
MockMvc是由spring-test包提供,实现了对Http请求的模拟,能够直接使用网络的形式,转换到Controller的调用,使得测试速度快、不依赖网络环境。同时提供了一套验证的工具,结果的验证十分方便。
接口
MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc。主要有两个实现:StandaloneMockMvcBuilder和DefaultMockMvcBuilder,分别对应两种测试方式,即独立安装和集成Web环境测试(并不会集成真正的web环境,而是通过相应的Mock API进行模拟测试,无须启动服务器)。MockMvcBuilders提供了对应的创建方法standaloneSetup方法和webAppContextSetup方法,在使用时直接调用即可。
2、为什么使用Mock对象
在以下情况可以采用模拟对象来替代真实对象:
- 真实对象的行为是不确定的(例如,当前的时间或温度);
- 真实对象很难搭建起来;
- 真实对象的行为很难触发(例如,网络错误);
- 真实对象速度很慢(例如,一个完整的数据库,在测试之前可能需要初始化);
- 真实的对象是用户界面,或包括用户界面在内;
- 真实的对象使用了回调机制;
- 真实对象可能还不存在;
- 真实对象可能包含不能用作测试(而不是为实际工作)的信息和方法。
使用Mockito一般分三个步骤:1、模拟测试类所需的外部依赖;2、执行测试代码;3、判断执行结果是否达到预期;
3、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
4、测试
4.1、初始化
import demo.springboot.test.controller.UserController;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringRunner.class)
@SpringBootTest
//测试环境使用,用来表示测试环境使用的ApplicationContext将是WebApplicationContext类型的
@WebAppConfiguration
public class UserControllerMyTest {
private MockMvc mockMvc;
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void create(){
//实例化方式一
//mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build();
//实例化方式二
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
}
4.2、测试方式
- mockMvc.perform ====> 执行一个请求。
- MockMvcRequestBuilders.get(“XXX”) ====> 构造一个请求。
- ResultActions.param ====> 添加请求传值
- contentType(MediaType.APPLICATION_JSON_UTF8_VALUE) ====> 设置数据格式:指定服务端能够接收的内容类型
- ResultActions.accept(MediaType.TEXT_HTML_VALUE)) ====> 设置返回类型:指定客户端能够接收的内容类型
- ResultActions.andExpect ====> 添加执行完成后的断言。
- ResultActions.andDo ====> 添加一个结果处理器,表示要对结果做点什么事情比如此处使用MockMvcResultHandlers.print()输出整个响应结果信息。
- ResultActions.andReturn ====> 表示执行完成后返回相应的结果。
4.3、测试代码示例
4.3.1、测试GET请求
@Test
public void getTest() throws Exception {
//路径参数测试1
mockMvc.perform(MockMvcRequestBuilders
.get("/user/{userName}","tester")
.contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
//路径参数测试二
//mockMvc.perform(MockMvcRequestBuilders
// .get("/user/{userName}/{text}","tester","哈哈")
// .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
// .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
// .andExpect(MockMvcResultMatchers.status().isOk())
// .andDo(MockMvcResultHandlers.print());
//表单参数测试一
//mockMvc.perform(MockMvcRequestBuilders
// .get("/user")
// .param("userName","小红")
// .param("text","你好")
// .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
// .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
// .andExpect(MockMvcResultMatchers.status().isOk())
// .andDo(MockMvcResultHandlers.print());
//表单参数测试二
MvcResult s = mockMvc.perform(MockMvcRequestBuilders
.get("/user?userName=小红&text=你好")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("你好"))
.andDo(MockMvcResultHandlers.print())
.andReturn();
System.out.println(s.getResponse().getContentAsString());
//路径参数使用 .get("/user/{参数1}/{参数2}",参数1,参数2)
//表单参数使用 .param("userName","小红")
}
@Test
public void getSequenceTest() throws Exception {
mockMvc.perform(MockMvcRequestBuilders
.get("/user/getSequence/{userName}","tester")
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk())
//对对象的参数进行校验
.andExpect(MockMvcResultMatchers.jsonPath("$.username").value("tester"))
.andDo(MockMvcResultHandlers.print());
}
4.3.2、测试POST请求
@Test
public void postTest() throws Exception {
User user = new User();
user.setUsername("小红");
user.setPasswd("123456");
System.out.println(new Date());
user.setCreateTime(new Date());
user.setStatus("2");
ObjectMapper objectMapper = new ObjectMapper();
//需要将对象转换成JSON字符串
String userStr = objectMapper.writeValueAsString(user);
mockMvc.perform(MockMvcRequestBuilders
.post("/user/save")
.content(userStr)
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print());
}
4.3.3、带有请求头/获取请求结果/中文乱码解决
@Test
public void test() throws Exception {
//测试获取Token
User user = new User();
user.setUserID("admin");
user.setUserName("admin");
user.setPassWord("admin");
//将USER转换为JSON字符串
ObjectMapper objectMapper = new ObjectMapper();
//需要将对象转换成JSON字符串
String userStr = objectMapper.writeValueAsString(user);
ResultActions resultActions =
mockMvc.perform(MockMvcRequestBuilders
.post("/getToken")
.content(userStr)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk());
// 解决中文乱码问题
resultActions.andReturn().getResponse().setCharacterEncoding("UTF-8");
resultActions.andDo(MockMvcResultHandlers.print());
// 测试使用Token发送请求
Map<String, Object> restResponse =
objectMapper.readValue(resultActions.andReturn().getResponse().getContentAsString()
, new TypeReference<Map<String, Object>>() {});
String token = restResponse.get("data").toString();
ResultActions testTokenActions =
mockMvc.perform(MockMvcRequestBuilders
.get("/testToken")
// 设置请求头
.header("token", token)
.contentType(MediaType.APPLICATION_JSON_VALUE)
.accept(MediaType.APPLICATION_JSON_VALUE))
.andExpect(MockMvcResultMatchers.status().isOk());
//解决中文乱码问题
testTokenActions.andReturn().getResponse().setCharacterEncoding("UTF-8");
testTokenActions.andDo(MockMvcResultHandlers.print());
}
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 程序员小航
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果