SpringBoot单元测试(二)MockMVC
介绍
MockMvc,从字面来理解,很好理解,主要是用来模拟MVC。简单来说,就是模拟可以从客户端请求后端的Controller类。
样例:
1. 非自动注入式
TestApplicationTests类已经有@RunWith(SpringRunner.class)和@SpringBootTest注解了,具体参考上一篇文章
SpringBoot 单元测试(一)SpringBootTest
package com.orjrs.spring.test.unit;
import com.orjrs.spring.test.TestApplicationTests;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.context.web.WebAppConfiguration;
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.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* MockMvcTest
*
* @author orjrs
* @date 2018-10-06 20:15
*/
@WebAppConfiguration // 1
public class MockMvcTest extends TestApplicationTests {
@Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
@Before // @Test注解的方法运行前执行,MockMvcBuilder构造MockMvc实例
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void post() throws Exception {
String name = "Smart LIU";
String msg = "您好";
mockMvc.perform(
MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
.contentType(MediaType.APPLICATION_JSON_UTF8)
//.content()
)
.andExpect(MockMvcResultMatchers.status().isOk())
//.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
}
2. 自动注入
package com.orjrs.spring.test.unit;
import com.orjrs.spring.test.TestApplicationTests;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.http.MediaType;
import org.springframework.test.context.web.WebAppConfiguration;
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.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
/**
* MockMvcTest
*
* @author orjrs
* @date 2018-10-21 16:12
*/
@WebAppConfiguration // 1
@AutoConfigureMockMvc // 开启MockMvc自动注解
public class AutoMockMvcTest extends TestApplicationTests {
// @Autowired
// private WebApplicationContext webApplicationContext;
@Autowired
private MockMvc mockMvc;
/*@Before // @Test注解的方法运行前执行,MockMvcBuilder构造MockMvc实例
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}*/
@Test
public void post() throws Exception {
String name = "Smart LIU";
String msg = "您好";
mockMvc.perform(
MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
.contentType(MediaType.APPLICATION_JSON_UTF8)
//.content()
)
.andExpect(MockMvcResultMatchers.status().isOk())
//.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
}
源码分析:
MockMvcBuilders: 主要是用来构造MockMvc的。它有两个方法,如下:
public class MockMvcBuilders {
public MockMvcBuilders() {
}
// 通过指定WebApplicationContext,根据上下文获取相应的Controller来构建MockMvc
public static DefaultMockMvcBuilder webAppContextSetup(WebApplicationContext context) {
return new DefaultMockMvcBuilder(context);
}
// 通过参数直接指定一组控制器来构建MockMVC
public static StandaloneMockMvcBuilder standaloneSetup(Object... controllers) {
return new StandaloneMockMvcBuilder(controllers);
}
}
AbstractMockMvcBuilder还实现了ConfigurableMockMvcBuilder接口,即有以下方法
package org.springframework.test.web.servlet.setup;
import javax.servlet.Filter;
import org.springframework.test.web.servlet.MockMvcBuilder;
import org.springframework.test.web.servlet.RequestBuilder;
import org.springframework.test.web.servlet.ResultHandler;
import org.springframework.test.web.servlet.ResultMatcher;
public interface ConfigurableMockMvcBuilder<B extends ConfigurableMockMvcBuilder<B>> extends MockMvcBuilder {
<T extends B> T addFilters(Filter... var1);// 添加过滤器
<T extends B> T addFilter(Filter var1, String... var2);// 添加过滤器
<T extends B> T defaultRequest(RequestBuilder var1);//默认的RequestBuilder,每次执行时会合并到自定义的RequestBuilder中,即提供公共请求数据的;
<T extends B> T alwaysExpect(ResultMatcher var1); // 定义全局的结果验证器,即每次执行请求时都进行验证的规则;
<T extends B> T alwaysDo(ResultHandler var1);// 定义全局结果处理器,即每次请求时都进行结果处理;
<T extends B> T dispatchOptions(boolean var1); // DispatcherServlet是否分发OPTIONS请求方法到控制器;
<T extends B> T apply(MockMvcConfigurer var1);
}
public interface MockMvcBuilder {
MockMvc build();
}
StandaloneMockMvcBuilder除了继承AbstractMockMvcBuilder之外,自己还提供了许多方法,这里不多说了。
MockMvc:
mockMvc.perform(
MockMvcRequestBuilders.post("/unit/sayHello/" + name + "/" + msg)
.contentType(MediaType.APPLICATION_JSON_UTF8)
//.content()
)
.andExpect(MockMvcResultMatchers.status().isOk())
//.andExpect(MockMvcResultMatchers.content().contentType("text/plain;charset=UTF-8"))
.andDo(MockMvcResultHandlers.print())
.andReturn();
}
perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理,返回ResultActions类;
andExpect:添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确;
andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台;
andReturn:最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理;
另外还提供了以下API:
setDefaultRequest:设置默认的RequestBuilder,用于在每次perform执行相应的RequestBuilder时自动把该默认的RequestBuilder合并到perform的RequestBuilder中;
setGlobalResultMatchers:设置全局的预期结果验证规则,如我们通过MockMvc测试多个控制器时,假设它们都想验证某个规则时,就可以使用这个;
setGlobalResultHandlers:设置全局的ResultHandler结果处理器;
RequestBuilder/MockMvcRequestBuilders
Request请求,有put、get、post、delete、patch、options、head、request、multipart、fileUpload、asyncDispatch请求方法。
MockHttpServletRequestBuilder和MockMultipartHttpServletRequestBuilder
主要是针对请求头的。有header、contentType、cookie、characterEncoding、requestAttr、sessionAttr、contextPath等方法