对Spring MVC接口进行Mock测试
文章插图
1. 前言在Java开发中接触的开发者大多数不太注重对接口的测试 , 结果在联调对接中出现各种问题 。 也有的使用Postman等工具进行测试 , 虽然在使用上没有什么问题 , 如果接口增加了权限测试起来就比较恶心了 。 所以建议在单元测试中测试接口 , 保证在交付前先自测接口的健壮性 。 今天就来分享一下胖哥在开发中是如何对Spring MVC接口进行测试的 。
在开始前请务必确认添加了Spring Boot Test相关的组件 , 在最新的版本中应该包含以下依赖:
本文是在Spring Boot 2.3.4.RELEASE下进行的 。
2. 单独测试控制层如果我们只需要对控制层接口(Controller)进行测试 , 且该接口不依赖@Service、@Component等注解声明的Spring Bean时 , 可以借助@WebMvcTest来启用只针对Web控制层的测试 , 例如
@WebMvcTest class CustomSpringInjectApplicationTests {@AutowiredMockMvc mockMvc;@SneakyThrows@Testvoid contextLoads() {mockMvc.perform(MockMvcRequestBuilders.get("/foo/map")).andExpect(ResultMatcher.matchAll(status().isOk(),content().contentType(MediaType.APPLICATION_JSON),jsonPath("$.test", Is.is("hello")))).andDo(MockMvcResultHandlers.print());} ? }
这种方式要快的多 , 它只加载了应用程序的一小部分 。 但是如果你涉及到服务层这种方式是不凑效的 , 我们就需要另一种方式了 。
3. 整体测试大多数Spring Boot下的接口测试是整体而又全面的测试 , 涉及到控制层、服务层、持久层等方方面面 , 所以需要加载比较完整的Spring Boot上下文 。 这时我们可以这样做 , 声明一个抽象的测试基类:
package cn.felord.custom; ? 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.test.web.servlet.MockMvc; ? ? /*** 测试基类 ,* @author felord.cn*/ @SpringBootTest @AutoConfigureMockMvc abstract class CustomSpringInjectApplicationTests {/*** The Mock mvc.*/@AutowiredMockMvc mockMvc;// 其它公共依赖和处理方法}
只有当@AutoConfigureMockMvc存在时MockMvc才会被注入Spring IoC 。
然后针对具体的控制层进行如下测试代码的编写:
【对Spring MVC接口进行Mock测试】 package cn.felord.custom; ? import lombok.SneakyThrows; import org.hamcrest.core.Is; import org.junit.jupiter.api.Test; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.ResultMatcher; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; ? import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; ? /*** 测试FooController.** @author felord.cn*/ public class FooTests extends CustomSpringInjectApplicationTests {/*** /foo/map接口测试.*/@SneakyThrows@Testvoid contextLoads() {mockMvc.perform(MockMvcRequestBuilders.get("/foo/map")).andExpect(ResultMatcher.matchAll(status().isOk(),content().contentType(MediaType.APPLICATION_JSON),jsonPath("$.test", Is.is("bar")))).andDo(MockMvcResultHandlers.print());} }
4. MockMvc测试集成测试时 , 希望能够通过输入URL对Controller进行测试 , 如果通过启动服务器 , 建立http client进行测试 , 这样会使得测试变得很麻烦 , 比如 , 启动速度慢 , 测试验证不方便 , 依赖网络环境等 , 为了可以对Controller进行测试就引入了MockMvc 。
MockMvc实现了对Http请求的模拟 , 能够直接使用网络的形式 , 转换到Controller的调用 , 这样可以使得测试速度快、不依赖网络环境 , 而且提供了一套验证的工具 , 这样可以使得请求的验证统一而且很方便 。 接下来我们来一步步构造一个测试的模拟请求 , 假设我们存在一个下面这样的接口:
@RestController @RequestMapping("/foo") public class FooController {@Autowiredprivate MyBean myBean; ?@GetMapping("/user")public Map bar(@RequestHeader("Api-Version") String apiVersion, User user) {Map map = new HashMap<>();map.put("test", myBean.bar());map.put("version", apiVersion);map.put("username", user.getName());//todo your businessreturn map;} }
参数设定为name=felord.cn --tt-darkmode-color: #809CB9;"> , 那么对应的HTTP报文是这样的:
GET /foo/user?name=felord.cn --tt-darkmode-color: #809CB9;">可以预见的返回值为:
{"test": "bar","version": "v1","username": "felord.cn" }
事实上对接口的测试可以分为以下几步 。
- 纠结|硬杠红米Note9Pro?iQOO Z1跌至1575,对比之后纠结了!
- 对手|一加9Pro全面曝光,或是小米11最大对手
- 作家|逾万名作家联名反对亚马逊有声书轻松退换政策
- 芯片|华米GTS2mini和红米手表哪个好 参数功能配置对比
- 速度|华为P50Pro或采用很吓人的拍照技术:液体镜头让对焦速度更快
- 时尚先生|小米雷军成2020年最出圈企业家:获时尚双刊年度人物
- 电信|巴西电信协会及运营商发文 反对限制华为5G
- 华为|骁龙870和骁龙855区别都是7nm芯片吗 性能对比评测
- 区企联企协|谋求更高质量的转型发展!区企联企协与区科技局成功举办科技考察对接活动
- 中国|对越南新增投资18亿?把30%的生产线转移?富士康真要跑了?