(十)从零搭建后端框架——MockMvc单元测试

前言

在功能开发完成后,虽然有专门的测试人员,但开发人员自身也要进行单元测试。

一般公司对BUG率和单元测试覆盖率都会有一定的要求,所以做好单元测试还是很有必要的。

后端提供的都是接口,本文使用MockMvc模拟接口进行测试。

具体实现

Maven依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
复制代码<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>

<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

为了防止测试对真实数据库数据产生影响,这里使用H2数据库,并进行参数配置。

参数配置

1
2
3
4
5
6
7
8
9
复制代码spring:
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:test;MODE=MYSQL;
schema: classpath:sqls/sys.sql
main:
banner-mode: off
mybatis:
mapper-locations: classpath*:sql-mappers/**/*.xml
  • spring.datasource.schema 指定建表语句文件
  • mybatis.mapper-locations 指定Mapper文件

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
复制代码@SpringBootTest
@AutoConfigureMockMvc
public class UserControllerTest {

@Autowired
private MockMvc mvc;

private static Gson gson = new GsonBuilder().serializeNulls().create();

@Test
@SqlGroup({
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, value = "classpath:h2/user/init-data.sql"),
@Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, value = "classpath:h2/user/clean-data.sql")
})
void getUser() throws Exception {
// 模拟GET请求
mvc.perform(get("/user/1")
// 请求参数类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 接收参数类型
.accept(MediaType.APPLICATION_JSON_UTF8))
// 结果验证
.andExpect(status().isOk())
.andExpect(jsonPath("code").value(200))
.andExpect(jsonPath("data").exists())
.andExpect(jsonPath("$['data']['account']").value("zhuqc1"))
.andExpect(jsonPath("$['data']['password']").value("password"))
.andExpect(jsonPath("$['data']['nickname']").value("zhuqc1"))
.andExpect(jsonPath("$['data']['email']").value("zqc@zqc.com"))
.andExpect(jsonPath("$['data']['phone']").value("13345678901"))
// 结果处理器
.andDo(MockMvcResultHandlers.print());
}

@Test
@SqlGroup({
@Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, value = "classpath:h2/user/init-data.sql"),
@Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, value = "classpath:h2/user/clean-data.sql")
})
void getUser2() throws Exception {
// 模拟GET请求,并返回结果
MvcResult result = mvc.perform(get("/user/1")
.accept(MediaType.APPLICATION_JSON_UTF8))
.andReturn();
MockHttpServletResponse response = result.getResponse();
JsonObject apiResult = JsonParser.parseString(response.getContentAsString()).getAsJsonObject();
JsonObject data = apiResult.getAsJsonObject("data").getAsJsonObject();

// 断言验证数据
Assertions.assertEquals(response.getStatus(), HttpStatus.OK.value());
Assertions.assertEquals(data.get("account").getAsString(), "zhuqc1");
Assertions.assertEquals(data.get("password").getAsString(), "password");
Assertions.assertEquals(data.get("nickname").getAsString(), "zhuqc1");
Assertions.assertEquals(data.get("email").getAsString(), "zqc@zqc.com");
Assertions.assertEquals(data.get("phone").getAsString(), "13345678901");
}

@Test
@SqlGroup({
@Sql(executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD, value = "classpath:h2/user/clean-data.sql")
})
void addUser() throws Exception {
User user = new User();
user.setAccount("zhuqc1");
user.setPassword("password");
user.setNickname("zhuqc1");
user.setEmail("zqc@zqc.com");
user.setPhone("13345678901");

// 模拟POST请求
mvc.perform(post("/user")
// 请求参数类型
.contentType(MediaType.APPLICATION_JSON_UTF8)
// 接收参数类型
.accept(MediaType.APPLICATION_JSON_UTF8)
// 请求参数
.content(gson.toJson(user)))
// 结果验证
.andExpect(status().isOk())
.andExpect(jsonPath("code").value(200))
.andExpect(jsonPath("data").value(1));
}
}
  • @SpringBootTest 指定测试类在SpringBoot环境下运行
  • @AutoConfigureMockMvc 用于自动配置MockMvc,配置后MockMvc类可以直接注入
  • @SqlGroup 指定测试方法执行前后的SQL语句

比如,可以在测试方法执行前,初始化数据;在测试方法执行后,清除数据。

MockMvc

MockMvc是接口测试的主入口,核心方法perform(RequestBuilder),
会自动执行SpringMVC的流程并映射到相应的控制器执行处理,方法返回值是ResultActions。

ResultActions

  • andExpect 添加ResultMatcher验证规则,验证执行结果是否正确。
  • andDo 添加ResultHandler结果处理器,比如打印结果到控制台。
  • andReturn 返回MvcResult执行结果,可以对结果进行自定义验证。

MockMvcResultMatchers

用于验证执行结果是否正确,详见测试方法getUser()。

MockMvcResultHandlers

结果处理器,表示要对结果做点什么事情。详见测试方法getUser()。

比如使用MockMvcResultHandlers.print()打印响应结果信息到控制台。如下:

响应结果

MvcResult

单元测试执行结果,可以对结果进行自定义验证,详见测试方法getUser2()。

源码

github.com/zhuqianchan…

往期回顾

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%