SpringBoot-Testing

在写上一篇IoCDI之前,本来想记录的是SpringBoot如何完成AutoConfiguration自动配置,但因为篇幅直接分离出来了一篇。这次又把Testing给分离了出来。

事情的起因是,写项目代码时,常常需要对自己写的部分进行测试和调试。根据自己以往的编程经验,个人习惯于写一点就运行一点,并通过断点调试来确认内存的运行状态,避免犯一些低级的逻辑错误。虽然公司有专门的测试岗位,但从代码提交到GitLab请求合并,到部署到测试服务器,到测试人员设计用例并测试,到反馈到开发人员,整个过程涉及多个人员,太过漫长。而一些代码本身就需要反复调试,例如写了一些数据库操作,需要确认数据库实际执行结果是否符合预期。例如一个循环的跳出是否符合预期。执行结果符合预期本身是个很玄乎的事,很多时候代码看起来没啥问题,跑起来却又满脸问号。询问同事,都回答说让测试去测。而我觉得开发人员有义务确保代码没有低级的逻辑错误。

JUnit

SpringBoot框架中,常用的测试框架是JUnit。现在最新版本SpringBoot3.0.5对应的Junit5版本,官方文档。公司内部使用的是Junit4

对于JUnit框架内部原理暂时没深入了解。从使用角度,常常会对需要测试的类,新生成一个对应的测试类,命名规范通常为 新测试类命 = 旧类命 + "Test"。例如有一个Calculator类,那会新定义一个CalculatorTest测试类,并在测试类中定义成员测试方法,对应于被测试类中的方法。在每个成员方法中添加注解@Test,通过IDE或者构建工具就可以自动执行测试方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import org.junit.Test;

public class CalculatorTest {

@Test
public void testAddition() {
// 编写测试代码,测试Addition方法是否按照预期工作
}

@Test
public void testSubtraction() {
// 编写测试代码,测试Subtraction方法是否按照预期工作
}

// 还可以编写其他测试方法...
}

在测试中,可以通过构建测试用例,并使用断言,将方法输出和预期输出进行对比。还可以使用代码覆盖率工具,来分析测试覆盖率。这些是JUnit核心功能,其他功能暂时还未深入了解。

Testing in SpringBoot

SpringBoot中,一个应用有什么功能,取决于在容器中有哪些Bean实例。例如我需要访问数据库,容器中必须要有JDBC相关的Bean,我需要处理web请求,容器中必须有TomcatSevlet相关的Bean

如果采用上文的方式去测试Spring项目中某个模块,那必然会报错。因为JUnit并不会像Spring一样启动,并将这些功能Bean添加到容器中。也就无法完成例如依赖注入等功能。

为了让JUnit能启动容器环境,Spring提供了@SpringBootTest注解。只需要在测试类前添加@SpringBootTest,就可以在测试时启动Spring容器。如果不指定注解的classes属性,也就是启动的配置类,那么会将主应用程序类,也就带有@SpringBootApplication注解的类作为配置类。

另外,如果使用的是JUnit4,还需要在测试类上额外添加@RunWith(SpringRunner.class)。需要这么做的原因涉及JUnit框架原理,在此不深究。

但问题是,使用@SpringBootTest注解时,会创建一个真实的SpringBoot上下文,并加载所有的Bean,这会导致测试的运行速度较慢。测试可能往往只是想测一个刚写完的某个方法,但却需要将许多不相关的Bean都加载进来,这会造成严重性能浪费。较长的测试启动时间也会大大降低测试时的主观感受。

要解决这个问题,就需要知道容器里的Bean是怎么样的方式被加载进去的,已经如何自定义加载需要的Bean,这也是下一篇要讨论的内容。

总结

JUnitJava中最公认的测试框架。使用时只需要在测试类的测试方法上加@Test注解,即可对目标方法进行测试。在测试类中,可以使用许多功能并生成测试报告,来判断目标方法是否按照预期执行。

由于JUnit框架默认不会启动Spring容器,而Spring应用的功能依赖于Spring容器。因此直接使用JUnit测试Spring项目中的类会发生错误。可以使用@SpringBootTest在测试类中启动Spring容器环境。


SpringBoot-Testing
http://dracoyus.github.io/2023/04/13/SpringBoot-Testing/
作者
DracoYu
发布于
2023年4月13日
许可协议