美文网首页程序员
高手都这么给 Spring MVC 做单元测试!

高手都这么给 Spring MVC 做单元测试!

作者: 程序员木子 | 来源:发表于2020-12-05 14:19 被阅读0次

    本章节主要讲解以下两部分内容:

    1、Mock 测试简介

    2、测试用例演示

    一、Mock 测试简介

    1、什么是 mock 测试

    在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个「虚拟的对象」来创建以便测试的测试方法,就是 「mock 测试」在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个「虚拟的对象」来创建以便测试的测试方法,就是mock 测试。

    虚拟的对象就是 mock 对象。

    mock 对象就是真实对象在调试期间的代替品。

    2、为什么使用 mock 测试

    避免开发模块之间的耦合

    轻量、简单、灵活

    3、MockMVC 介绍

    基于 RESTful 风格的 SpringMVC 的测试,我们可以测试完整的 Spring MVC 流程,即从 URL 请求到控制器处理,再到视图渲染都可以测试。

    1)MockMvcBuilder

    MockMvcBuilder 是用来构造 MockMvc 的构造器,其主要有两个实现:StandaloneMockMvcBuilder 和 DefaultMockMvcBuilder,对于我们来说直接使用「静态工厂 MockMvcBuilders 创建」即可。

    2)MockMvcBuilders

    负责创建 MockMvcBuilder 对象,有两种创建方式:

    standaloneSetup(Object... controllers):通过参数指定一组控制器,这样就不需要从上下文获取了。

    「webAppContextSetup」(WebApplicationContext wac):指定 WebApplicationContext,将会从该上下文获取相应的控制器并得到相应的 MockMvc,本章节下面测试用例均使用这种方式创建 MockMvcBuilder 对象。

    3)MockMvc

    对于服务器端的 SpringMVC 测试支持主入口点。通过 MockMvcBuilder 构造 MockMvcBuilder 由 MockMvcBuilders 建造者的静态方法去建造。

    核心方法:perform(RequestBuilder rb) -- 执行一个 RequestBuilder 请求,会自动执行 SpringMVC 的流程并映射到相应的控制器执行处理,该方法的返回值是一个 ResultActions。

    4)ResultActions

    (1)「andExpect」:添加 ResultMatcher 验证规则,验证控制器执行完成后结果是否正确;

    (2)「andDo」:添加 ResultHandler 结果处理器,比如调试时打印结果到控制台;

    (3)「andReturn」:最后返回相应的 「MvcResult」;然后进行自定义验证 / 进行下一步的异步处理;

    5)MockMvcRequestBuilders

    用来构建请求的,其主要有两个子类 「MockHttpServletRequestBuilder *和」MockMultipartHttpServletRequestBuilder*(如文件上传使用),即用来 Mock 客户端请求需要的所有数据。

    6)MockMvcResultMatchers

    (1)用来匹配执行完请求后的「结果验证」

    (2)如果匹配失败将抛出相应的异常

    (3)包含了很多验证 API 方法

    7)MockMvcResultHandlers

    (1)结果处理器,表示要对结果做点什么事情

    (2)比如此处使用 MockMvcResultHandlers.print() 输出整个响应结果信息

    8)MvcResult

    (1)单元测试执行结果,可以针对执行结果进行「自定义验证逻辑」

    二、测试用例演示

    1、添加依赖

    <!-- spring 单元测试组件包 -->

    <dependency>

     <groupId>org.springframework</groupId>

     <artifactId>spring-test</artifactId>

     <version>5.0.7.RELEASE</version>

    </dependency>

    <!-- 单元测试Junit -->

    <dependency>

     <groupId>junit</groupId>

     <artifactId>junit</artifactId>

     <version>4.12</version>

    </dependency>

    <!-- Mock测试使用的json-path依赖 -->

    <dependency>

     <groupId>com.jayway.jsonpath</groupId>

     <artifactId>json-path</artifactId>

     <version>2.2.0</version>

    </dependency>

    前两个 jar 依赖我们都已经接触过了,对于返回视图方法的测试这两个 jar 依赖已经足够了,第三个 jar 依赖是用于处理返回 Json 数据方法的,这里要明白每个 jar 的具体作用。

    2、被测试的方法

    @RequestMapping(value ="editItem")

    public String editItem(Integer id, Model model) {

    Item item = itemService.getItemById(id);

    model.addAttribute("item", item);

    return"itemEdit";

    }

    @RequestMapping(value ="getItem")

    @ResponseBody

    public Item getItem(Integer id) {

    Item item = itemService.getItemById(id);

    returnitem;

    }

    这里我们提供了两个方法,一个是返回视图的方法,另一个是返回 Json 数据的方法,下面我们会给出测试类,分别对这两个方法进行测试。

    3、测试类:ItemMockTest

    @RunWith(SpringJUnit4ClassRunner.class)

    @ContextConfiguration(locations ="classpath:spring/*.xml")

    @WebAppConfiguration

    public class ItemMockTest {

    @Autowired

    private WebApplicationContext context;

    private MockMvc mockMvc;

    @Before

    public voidinit() {

    mockMvc = MockMvcBuilders.webAppContextSetup(context).build();

    }

    }

    这里前两个注解就不再解释了,我们在学习 Spring 与 Junit 整合的时候已经讲解过了,这里说一下第三个注解:@WebAppConfiguration:可以在单元测试的时候,不用启动 Servlet 容器,就可以获取一个 Web 应用上下文。

    1)返回视图方法测试

    @Test

    public voidtest() throws Exception {

    MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/editItem").param("id","1"))

    .andExpect(MockMvcResultMatchers.view().name("itemEdit"))

    .andExpect(MockMvcResultMatchers.status().isOk())

    .andDo(MockMvcResultHandlers.print())

    .andReturn();

    Assert.assertNotNull(result.getModelAndView().getModel().get("item"));

    }

    这三句代码是我们对结果的期望,最后打印出了结果,说明执行成功,所有期望都达到了,否则会直接报错。从结果中我们就可以看到这个请求测试的情况。

    2、返回 Json 数据方法

    @Test

    public void test1() throws Exception {

    mockMvc.perform(MockMvcRequestBuilders.get("/getItem")

    .param("id","1")

    .accept(MediaType.APPLICATION_JSON))

    .andExpect(MockMvcResultMatchers.status().isOk())

    .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON))

    .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1))

    .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("IPhone X"))

    .andDo(MockMvcResultHandlers.print())

    .andReturn();

    }

    在这个方法中比较特殊的就是设置 MediaType 类型,因为都是使用 Json 格式,所以设置了 MediaType.APPLICATION_JSON,jsonPath 用于比对期望的数据是否与返回的结果一致,这里需要注意的是 "$.id" 这 key 的种形式。

    四、小结

    这里只是用到了 MockMvc 很小一部分知识,更加深入学习会使你养成一种良好编写单元测试的习惯,这是十分难得的一种好习惯,推荐去看官方文档,然后动手去测试一下,为你编写的每一个 Controller 方法进行测试,保证他们的可靠性。

    相关文章

      网友评论

        本文标题:高手都这么给 Spring MVC 做单元测试!

        本文链接:https://www.haomeiwen.com/subject/onlvwktx.html