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

网友投稿 393 2022-08-28


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

目录导入静态工具方法初始化MockMvc执行测试测试GET接口测试POST接口测试文件上传定义预期结果写在最后

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

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

org.springframework.boot

spring-boot-starter-web

!<-- Spring测试框架 -->

org.springframework.boot

spring-boot-starter-test

test

commons-io

commons-io

2.11.0

导入静态工具方法

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

import static org.springframework.test.web.servlet.setup.MockMvcBuilders.*;

import static org.springframework.test.web.servlet.request.MocZJXqOrkMvcRequestBuilders.*;

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服务接口进行单元测试,不要把基础的功能验证工作都交给测试童鞋,应该通过单元测试来保证代码迭代的稳定性。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:python文件切割(python字符串的切割)
下一篇:python爬虫使用Cookie登录(python cookiejar)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~