Spring Controller层测试 – 05 SpringBootTest & WebServer

在使用@SpringBootTest测试时可以指定一个端口,如 @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT),这样在测试时会启动Spring内嵌的Http Server。 这时就可以使用一个 RestTemplate 或者 TestRestTemplate

使用RANDOM_PORT和DEFINED_PORT的区别在于前着使用的是配置文件中的端口号( server.port,默认值为8080),后者使用的是一个随机端口号。在进行并行测试的时候可以使用随机端口号以避免端口冲突。

看下测试代码:

Web Server测试

这里依然使用 SpringRunner执行测试。同时使用 @SpringBootTest注解的 RANDOM_PORT 模式来得到一个内嵌的WebServer运行当前应用。

测试代码中使用 RestTemplate来触发请求,这个过程和使用外部服务器很像。

测试中的assertion现在有了一点儿变化,因为要验证的返回值由 MockHttpServletResponse变成了 ResponseEntity

TestRestTemplate

因为使用了 @SpringBootTest注解,就可以使用 @Autowired注解来获取 TestRestTemplate的实例。这个 TestRestTemplate实例的作用和常见的 RestTemplate实例几乎没有任何区别,只是添加了一些额外的能力。实际上,可以将 TestRestTemplate视为 RestTemplate在测试环境的装饰类。

参与测试的角色关系如下图:

关于性能

也许我们会觉得第一个方案会更加有性能优势,因为它不需要加载Spring Context。事实上确实如此。但是即使加载了SpringContext,也不会造成特别恐怖的影响,因为在同一个Test Suite中,已经加载的Spring Context是可以重用的。

不过Spring Context重用也会导致一些问题,比如一些测试方法对公共的Bean做了修改就可能会影响到其他测试方法。此时可以使用 @DirtiesContext注解来要求重新加载Context。

总结

到现在为止我们从轻到重共介绍了四种SpringBoot Controller测试方案。

虽然我们的目标一直都是对Controller层进行测试,但是从第一种测试方案(Standalone MockMVC)到现在,测试的角度还是有些变化的。一开始我们只是会加载测试的Controller类,却不会加载其周边的一些角色如Filter或Advice。到现在这个方案里我们启动了内嵌的WebServer,加载了整个SpringBoot Context。

目前这个方案是提到的四个测试方案里最重的一个,也是离单元测试的概念最远的一个。

下面说几个使用建议:

  • 如果在单元测试中关注Controller的逻辑,优先选择第一种方案:Standalone MockMVC方案;
  • 如果要测试Web层的其它角色(Filter或Advice)的行为,优先选择第四种测试方案执行集成测试;
  • 避免将单元测试和集成测试混在一起,最好分开来写。

其他

示例代码可在CSDN下载,地址:https://download.csdn.net/download/tianxiexingyun/11065824

参考文档:https://thepracticaldeveloper.com/2017/07/31/guide-spring-boot-controller-tests/


发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据