springboot 单元测试实践3 新建http请求接口

本文重点来写点代码,对spring boot中http接口的返回进行单测。我们在springboot单元测试实践1中,已经写了如何mockcontroller的请求,测试controller中的逻辑,并简单针对返回体response进行了简单的测试。

在实际的生产环境中,spring boot对外提供的http接口的返回,根据具体的业务场景可能是个很复杂的数据结构。目前,大多数前后端分离的项目,返回的内容都是一整段的json格式的数据。

所以,我们对response做测试,大部分就是在针对response中返回的json做校验,json中有可能返回的是array,map等嵌套的复杂结构。

新建http请求接口

在前文的DemoController中,新建几个http的请求接口

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
typescript复制代码import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
@Slf4j
public class DemoController {

@GetMapping("/log")
public String log() {
log.info("test print log");
return "log";
}

@GetMapping("/list")
public List<String> stringList() {

List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
return list;
}

@GetMapping("/map")
public Object mapList() {
List<String> list = new ArrayList<>();
list.add("one");
list.add("two");
list.add("three");
return Map.of("list", list);
}

@GetMapping("/result")
public Object resultList() {
Result result1 = new Result();
result1.setKey("key1");
Result result2 = new Result();
result2.setKey("key2");
return List.of(result1, result2);
}

@Getter
@Setter
private class Result {
private String key;
private String value;
}
}

内容中新增了/api/list 、 /api/map、 /api/result 三个接口

/api/list 的单测

/api/list 主要是用来模拟直接返回一个list的列表,也就是说实际的response是下面这个样子的

1
css复制代码    ["one", "two", "three"]

针对 /api/list,写了下面的测试case

1
2
3
4
5
6
7
8
less复制代码@Test
void stringList() throws Exception {
this.mockMvc
.perform(MockMvcRequestBuilders.get("/api/list"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.iterableWithSize(3)));
}

.andDo(print()) 实际上就是用来在控制台打印具体的response内容,这样方便比对response的内容进行针对性的测试

jsonPath方法是用来将response按照json的格式来进行解析,”$”符号代表着json的根对象,因为我们返回的是个list,所以根对象实际指的就是当前返回的array数组,这里我们期望返回的array列表的大小是3

/api/map 的单测

/api/map 主要是用来模拟直接返回一个map,也就是说实际的response是下面的这个样子的, 这里我们直接使用andDo(print())的控制台的打印来检查返回内容

image.png

针对 /api/map, 写了下面的测试case

1
2
3
4
5
6
7
8
9
10
11
less复制代码@Test
void mapList() throws Exception {
this.mockMvc
.perform(MockMvcRequestBuilders.get("/api/map"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$").isMap())
.andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasKey("list")))
.andExpect(MockMvcResultMatchers.jsonPath("$.list", Matchers.iterableWithSize(3)))
.andExpect(MockMvcResultMatchers.jsonPath("$.list[0]", Matchers.is("one")));
}

首先,我们测试jsonPath拿到的根对象的内容是不是一个map,再来检查map返回的内容中是不是有一个list的key,再来检查list返回的结果的大小是不是3个,最后来获取list中第一个对象的内容

/api/result接口的单测

/api/result 主要是用来模拟直接返回一个对象的列表,我们直接使用andDo(print())的控制台的打印来检查返回内容

image.png

针对 /api/result,写了下面的测试case

1
2
3
4
5
6
7
8
9
10
11
12
13
less复制代码@Test
void resultList() throws Exception {
this.mockMvc
.perform(MockMvcRequestBuilders.get("/api/result"))
.andDo(print())
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.jsonPath("$").isArray())
.andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.iterableWithSize(2)))
.andExpect(
MockMvcResultMatchers.jsonPath(
"$", Matchers.everyItem(Matchers.allOf(Matchers.hasKey("key")))))
.andExpect(MockMvcResultMatchers.jsonPath("$[0].key", Matchers.is("key1")));
}

我们先测试jsonPath拿到的根对象是不是一个array数组,再检查列表中的大小是不是2,再检查列表中所有的对象,都包含key这个字段,最后检查列表中的第一个对象的key字段对应的值为key1

好了,针对json的测试目前也就这么多,更复杂的测试,可以多去看看MockMvcResultMatchers中提供的api和Matchers中提供的校验方法。

就到这里了,如果有复杂的场景,也可以在评论里写出来,一起来玩转业务场景的各种单测case

本文转载自: 掘金

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

0%