Spring MVC中的Controller进行单元测试的实现

 更新时间:2022年02月17日 08:58:31   作者:nuccch  
本文主要介绍了如何对Spring MVC中的Controller进行单元测试的实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

对Controller进行单元测试是Spring框架原生就支持的能力,它可以模拟HTTP客户端发起对服务地址的请求,可以不用借助于诸如Postman这样的外部工具就能完成对接口的测试。
具体来讲,是由Spring框架中的spring-test模块提供的实现,详见MockMvc

如下将详细阐述如何使用MockMvc测试框架实现对“Spring Controller”进行单元测试,基于Spring Boot开发框架进行验证。
添加测试框架依赖:

<!-- Spring框架 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
!<-- Spring测试框架 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>
<!-- 文件操作工具 -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.11.0</version>
</dependency>

导入静态工具方法

为了便于在编写测试用例时直接调用测试框架自带的静态方法,首先需要导入这些静态工具方法。
需要导入的静态方法如下:

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.setup.SharedHttpSessionConfigurer.*;

初始化MockMvc

初始化MockMvc有2种方式:
方式1:明确指定需要测试的“Controller”类进行配置
方式2:基于Spring容器进行配置,包含了Spring MVC环境和所有“Controller”类,通常使用这种方式。

@SpringBootTest
public class TestControllerTest {

    MockMvc mockMvc;

    // 初始化MockMvc
    @BeforeEach
    void setUp(WebApplicationContext wac) {
        // 方式1:明确指定需要测试的“Controller”类
        this.mockMvc = MockMvcBuilders.standaloneSetup(new TestController()).build();

        // 方式2:基于Spring容器进行配置,包含了Spring MVC环境和所有“Controller”类。
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
}

另外,还可以对MockMvc进行全局配置。

// 全局配置MockMvc
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
        .defaultRequest(get("/").accept(MediaType.APPLICATION_JSON)) // 默认请求路径
        .apply(sharedHttpSession()) // 配置session
        .alwaysExpect(status().isOk()) // 预期响应状态码
        .alwaysExpect(content().contentType("application/json;charset=UTF-8")) // 预期内容类型
        .build();

执行测试

MockMvc支持对常见的HTTP方法,如:GET,POST,PUT,DELETE等,甚至还支持文件上传请求。

测试GET接口

// 访问GET接口:不带参数
@Test
public void testSimpleGet() throws Exception {
    MvcResult result = this.mockMvc.perform(get("/test/simple/get")
            .accept(MediaType.APPLICATION_JSON)) // 接受JSON格式响应消息
            .andReturn(); // 获取返回结果
    Assertions.assertEquals("OK", result.getResponse().getContentAsString());
}

// 访问GET接口:带URL参数
@Test
public void testParamGet() throws Exception {
    int id = 10;
    // 方式1:在URI模板中指定参数
    //MvcResult result = this.mockMvc.perform(get("/test/param/get?id={id}", id).accept(MediaType.APPLICATION_JSON)).andReturn();

    // 方式2:通过param()方法指定参数
    //MvcResult result = this.mockMvc.perform(get("/test/param/get").param("id", String.valueOf(id)).accept(MediaType.APPLICATION_JSON)).andReturn();

    // 方式3:通过queryParam()方法指定参数
    MvcResult result = this.mockMvc.perform(get("/test/param/get").queryParam("id", String.valueOf(id)).accept(MediaType.APPLICATION_JSON)).andReturn();
    Assertions.assertEquals("OK: " + id, result.getResponse().getContentAsString());
}

测试POST接口

// 传递表单参数
@Test
public void testSimplePost() throws Exception {
    int id = 10;

    // 调用param()方法传递参数
    MvcResult result = this.mockMvc.perform(post("/test/simple/post")
            .param("id", String.valueOf(id))
            .contentType(MediaType.APPLICATION_FORM_URLENCODED)
            .accept(MediaType.APPLICATION_JSON))
            .andReturn();
    Assertions.assertEquals("{\"id\":10}", result.getResponse().getContentAsString());
}

// 传递JSON参数
@Test
public void testSimplePostJson() throws Exception {
    // 调用content()方法传递json字符串参数
    Subject subject = new Subject();
    subject.setId(10);
    String content = JSON.toJSONString(subject);
    MvcResult result = this.mockMvc.perform(post("/test/simple/post/json")
            .content(content)
            .contentType(MediaType.APPLICATION_JSON)
            .accept(MediaType.APPLICATION_JSON))
            .andReturn();
    Assertions.assertEquals("{\"id\":10}", result.getResponse().getContentAsString());
}

测试文件上传

@Test
public void testFileUploadSingle() throws Exception {
    File file = new File("C:\\Users\\xxx\\Downloads\\test.jpg");
    String fileName = FilenameUtils.getName(file.getName());
    byte[] bytes = FileUtils.readFileToByteArray(file);
    MockMultipartFile mockMultipartFile = new MockMultipartFile("file", fileName, MediaType.MULTIPART_FORM_DATA_VALUE, bytes);
    this.mockMvc.perform(multipart("/test/upload/single").file(mockMultipartFile))
                .andExpect(status().isOk())
                .andExpect(content().string("OK"))
                .andDo(print());
}

定义预期结果

断言响应结果时,有2种方式:
1.使用JUnit提供的Assert断言工具判断返回结果,这是一种非常普遍和常见的方式
2.在MockMvc框架中可以通过andExpect()方法定义一个或多个预期结果,当其中一个期望结果断言失败时,就不会断言其他期望值了

// 使用Junit断言工具判断返回结果是否符合预期
@Test
public void testAssertResult() throws Exception {
    MvcResult result = this.mockMvc.perform(get("/test/simple/get").accept(MediaType.APPLICATION_JSON)).andDo(print()).andReturn();
    Assert.assertEquals("OK", result.getResponse().getContentAsString());
}

// 在MockMvc框架中定义预期结果
@Test
public void testExpectations() throws Exception {
    this.mockMvc.perform(get("/test/simple/get").accept(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())        // 预期响应状态码为200
            .andExpect(content().string("OK")) // 预期返回值为字符串“OK”
            .andDo(print());
}

相比于使用Junit的断言工具判断返回结果,在MockMvc框架中直接定义预期结果进行断言检查更加简洁。

写在最后

使用Spring提供的测试框架MockMvc可以非常方便地实现对HTTP服务接口进行单元测试,不要把基础的功能验证工作都交给测试童鞋,应该通过单元测试来保证代码迭代的稳定性。

到此这篇关于Spring MVC中的Controller进行单元测试的实现的文章就介绍到这了,更多相关Spring MVC Controller单元测试内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java设计模式之策略模式深入刨析

    Java设计模式之策略模式深入刨析

    策略模式属于Java 23种设计模式中行为模式之一,该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。本文将通过示例详细讲解这一模式,需要的可以参考一下
    2022-05-05
  • java页面中文乱码的解决办法

    java页面中文乱码的解决办法

    做java开发的朋友碰到最多的就是中文乱码这个问题了,下面介绍页面提交时与url中文乱码的一些解决办法
    2013-11-11
  • java输入数字,输出倒序的实例

    java输入数字,输出倒序的实例

    这篇文章主要介绍了java输入数字,输出倒序的实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • 3行代码快速实现Spring Boot Oauth2服务功能

    3行代码快速实现Spring Boot Oauth2服务功能

    oauthserver是一个基于Spring Boot Oauth2的完整的独立的Oauth服务器。仅仅需要创建相关数据表,修改数据库的连接信息,你就可以得到一个Oauth服务器。这篇文章给大家介绍3行代码快速实现Spring Boot Oauth2服务功能,需要的朋友参考下吧
    2018-04-04
  • Java虚拟机运行时栈的栈帧

    Java虚拟机运行时栈的栈帧

    本节将会介绍一下Java虚拟机栈中的栈帧,会对栈帧的组成部分(局部变量表、操作数栈、动态链接、方法出口)分别进行介绍,最后还会通过javap命令反解析编译后的.class文件,进行分析方法执行时的局部变量表、操作数栈等
    2021-09-09
  • Java Chassis3负载均衡选择器技术解密

    Java Chassis3负载均衡选择器技术解密

    这篇文章主要为大家介绍了Java Chassis3负载均衡选择器技术解密,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2024-01-01
  • 详解Java设计模式编程中的依赖倒置原则

    详解Java设计模式编程中的依赖倒置原则

    这篇文章主要介绍了详解Java设计模式中的依赖倒置原则,针对面对对象编程中的抽象的运用,需要的朋友可以参考下
    2016-02-02
  • IntelliJ IDEA(2017)安装和破解的方法

    IntelliJ IDEA(2017)安装和破解的方法

    这篇文章主要介绍了IntelliJ IDEA(2017)安装和破解的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • 如何两步解决maven依赖导入失败的问题

    如何两步解决maven依赖导入失败的问题

    这篇文章主要介绍了如何两步解决maven依赖导入失败的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • JAVA8 stream中三个参数的reduce方法对List进行分组统计操作

    JAVA8 stream中三个参数的reduce方法对List进行分组统计操作

    这篇文章主要介绍了JAVA8 stream中三个参数的reduce方法对List进行分组统计操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08

最新评论