spring boot大家都会编写接口,但是少有人知道接口集成测试如何编写更优雅

547 阅读3分钟

大家好,这里是小奏,觉得文章不错可以关注公众号小奏技术

背景

相信初学spring boot的同学在各大培训视频或者教程中都会教你如何编写接口。

比如我们要写一个接口很简单

@RestController
@RequestMapping("")
@Slf4j
public class XiaoZouController {


    @GetMapping("/xiaozou")
    public String testByXiaoZouJiShu(TestDTO testDTO) {
        return testDTO;
    }
}

加几个注解,一个接口就完成了。

如果要测试我们一般就是通过postman或者apifox来测试。

使用这两种方式测试有个缺点就是测试用例很难复用,其次无法在ci/cd中进行自动化测试。

部分api管理工具支持保存测试用例,但是始终是和代码分离的,不利于维护

所以为了接口的测试,我们需要编写集成测试。

遗憾的是很多开发很少了解在spring boot中如何编写集成测试,接下来我们就来详细讨论下spring boot中的集成测试

集成测试

spring boot中集成测试的方式有很多,我们接下来一一讨论,看看哪种方式最合适、最优雅

手动注入controller进行测试

spring boot提供了@SpringBootTest注解来进行集成测试。

一般人测试controller都会这样测试

@SpringBootTest
@Profile("dev")
class XiaoZouController {

    @Autowired
    private XiaoZouController xiaoZouController;

    @Test
    public void testController() {
        TestDTO testDTO = new TestDTO();
        String xiaoZouJiShu = xiaoZouController.testByXiaoZouJiShu(testDTO);
        assertEquals("xiaoZouJiShu", xiaoZouJiShu);
    }

}

使用这种方式进行测试有几个缺点

  1. 无法模拟http请求
  2. 仅能测试controller的代码逻辑,实际测试也就是server的逻辑
  3. 像一些http中比如headercookie等信息无法模拟,比如我们有一些切面进行了请求头的处理,比如我们从header中获取了uid等信息,这种情况下我们就无法进行测试

基于TestRestTemplate进行测试

如果我们想要模拟http请求,我们可以使用TestRestTemplate来进行测试

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Profile("dev")
public class XiaoZouController {

    @LocalServerPort
    private int port;


    @Autowired
    private TestRestTemplate restTemplate;


    @Test
    void greetingShouldReturnDefaultMessage() throws Exception {
        assertThat(this.restTemplate.getForObject("http://localhost:" + port + "/xiaozou", String.class)).contains("xiaozou");
    }
    
}
  1. @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)表示随机端口启动
  2. @LocalServerPort表示获取随机端口
  3. 使用TestRestTemplate是来模拟http请求的调用

这种方式测试也有缺点

  1. 启动了一个本地服务器,启动慢
  2. 对于结果校验没有提供开箱即用的断言机制

基于MockMvc进行测试

如果我们想要本地不启动服务器,只是测试服务器下面的层次,我们可以使用MockMvc来进行测试

这与处理真实的http请求处理方式一样,但是没有服务器启动成本

测试代码如下

@SpringBootTest
@AutoConfigureMockMvc
@Profile("dev")
public class XiaoZouControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @Test
    void greetingShouldReturnDefaultMessage() throws Exception {
        Long uid = 12345L;

        mockMvc.perform(MockMvcRequestBuilders.get("/xiaozou")
                .header("uid", uid)
                .contentType(MediaType.APPLICATION_JSON))
            .andExpect(status().isOk())
            .andExpect(jsonPath("$.code").value(200))
            .andExpect(jsonPath("$.data.uid").value(uid))
            .andExpect(jsonPath("$.data.version").doesNotExist())
            .andExpect(jsonPath("$.data.deviceId").value(IsNull.nullValue()));
    }

}

  1. 添加@AutoConfigureMockMvc注解自动注入MockMvc
  2. 通过@Autowired注入MockMvc对象
  3. 通过mockMvc进行http请求模拟
  4. 通过.hearder模拟header信息
  5. 通过.contentType模拟content-type信息
  6. 通过.andExpect进行结果校验
  7. 通过jsonPath进行json结果校验

总结

spring boot中测试controller有多种方式。

但是我觉得最好的方式还是通过@AutoConfigureMockMvc进行测试

不用启动服务器,测试速度快,而且可以模拟http请求,对于结果校验也提供了很多的断言机制。

对于一些经常变化的业务接口写集成测试的意义不是特别大。

是否需要编写集成测试还是要看接口的重要程度、项目的时间等多方面因素来决定。

小伙子,刀给你了,什么时候用你自己决定啦

参考