场景描述

需要对 api 编写测试类,可以采用的方式:

  1. MockMvc
  2. RestTemple

但是由于 MockMvc 的结果值是字符串,虽然提供了 jsonPath 方法解析,但是处理过程丧失了面向对象的优雅,可能其对于 controller 层作单元测试,结合 MockBean,应当会更方便,轻量;而在处理完整的 api 测试,使用 restTemplate 通过泛型可以直接获取到结果对象,处理过程更灵活。

注意事项

获取端口号

ps:使用 RestTemplate 是需要获取端口号的。
在启用 @SpringBootTest 时,无法直接从配置文件读取端口号,需要指定 :

1
2
3
4
5
6
@SpringBootTest(
classes = SampleApplication.class,
// 启用配置文件中定义的端口号
// 也可以通过枚举值切换为随机端口等
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT
)

否则会出现 -1 或 null 的情况,之后可以通过常规的 spring 注入方式,来获取端口号,如:

1
2
3
4
5
6
7
8
9
10
// 1. server.port 或 local.server.port
@Value("${server.port}")

// 2. @Value("${local.server.port}") 等价注解
@LocalServerPort

// 3. 环境变量
@Autowired
Environment environment;
this.environment.getProperty("server.port")

MockMvc

期间也是测试了 MockMvc 的使用,需要 @AutoConfigureMockMvc 注解在测试类上,启用相关配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@SpringBootTest
@AutoConfigureMockMvc
class WebTest {
@Autowired
MockMvc mockMvc;

void testMockMvc() {
String expected = "预期的 json 字符串";
mockMvc.perform(
MockMvcRequestBuilders
.get("路由")
)
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().json(expected))
.andDo(MockMvcResultHandlers.print());
}
}


使用异常

但使用过程并不顺利,遇到了以下异常:

1
2
3
4
5
6
7
8
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.NullPointerException

at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:626)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
at org.springframework.test.web.servlet.TestDispatcherServlet.service(TestDispatcherServlet.java:72)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:733)

通过异常信息,只能获取到空指针异常,无法直接定位到触发原因,但实际上是由于测试时,没有添加请求参数引起的,因此在遇到类似的异常时,需要注意请求本身是否存在违规的操作,缺失 header、参数等信息。

评论