前言
在上篇文章《SpringBoot单元测试实践——数据隔离篇》中,我们讨论了如何进行数据隔离,但是无论哪种方式,都无法做到完全的数据隔离,因为我们始终依赖了一个外部的数据库,不管是开发环境亦或是测试环境,而对于外部的数据源,我们是无法进行管控的,我们无法保证有谁会对我们依赖的数据库做什么操作,因此无法保证我们单元测试的准确性。因此,神器TestContainers
立功的时候到了,它是一个Java的三方库,它的功能很简单,就是可以在我们运行单元测试时,临时帮我们拉起一个Doker镜像,比如我临时拉一个MySQL镜像起来,那它就是一个完全独立的数据库,只用于本次测试,测试结束后又会自动销毁。
依赖配置
首先它的功能是拉起一个Doker镜像,那我们的单元测试环境中必须要安装了Docker,这是前提。然后需要配置我们的maven依赖:
org.testcontainers
testcontainers
1.18.3
test
org.testcontainers
mysql
1.18.3
test
org.testcontainers
junit-jupiter
1.18.3
test
测试代码
配置完依赖之后,就可以开始写我们的单元测试代码了:
@Testcontainers
@SpringBootTest
public class ContainersTest {
/**
* 通过@Container注解标记这是一个container
*/
@Container
public MySQLContainer mysqlContainer = new MySQLContainer(DockerImageName.parse("mysql:8.0-debian")).withExposedPorts(3306);
/**
* 覆盖数据库配置
*/
@DynamicPropertySource
public void dynamicProperties(DynamicPropertyRegistry registry) {
registry.add("spring.datasource.url", () -> mysqlContainer.getJdbcUrl());
registry.add("spring.datasource.driverClassName", () -> mysqlContainer.getDriverClassName());
registry.add("spring.datasource.username", () -> mysqlContainer.getUsername());
registry.add("spring.datasource.password", () -> mysqlContainer.getPassword());
}
/**
* 测试用例
*/
@Sql(
scripts = "create-data.sql",
config = @SqlConfig(transactionMode = ISOLATED)
)
@Test
public void testSaveOrUpdate() {
//do something db operation
}
}
@Testcontainers
是一个Junit Jupiter的扩展,它会在测试运行前后自动启动和关闭我们的容器,即下面的@Container
注解标记的容器。MySQLContainer
定义了一个MySQL容器
,创建方式是通过Docker镜像
,版本是mysql:8.0-debian
,这个容器会在测试运行前启动。@DynamicPropertySource
来覆盖了原来的配置,这个在之前的《SpringBoot单元测试实践——配置隔离篇》。中有讲到过。@Sql
注解用于测试前来执行一段SQL脚本,用于初始化数据库。经过这些配置之后,那我们每次运行单元测试,它都会拉起一个MySQL镜像,然后我们获取它的数据信息,替换掉原来的配置,并且初始化数据。就可以保证每次运行单元测试,都有一个干净的环境,并且不会受到其它外部因素的影响。
总结
上面介绍了如何使用TestContainers
来自动运行Docker镜像,从而保证数据的隔离,而且不仅仅是数据库,其它的包括Redis、Kafka等中间件,都可以通过这种方式进行隔离,这样就可以保证我们的单元测试完全是独立运行的,可以保证它的稳定性
与正确性
。但是它不是所有的场景都适用,首先需要有Docker环境
,其次拉起很多镜像的话,会对内存有要求
,而且单元测试的运行时间也会变得更长
。大家可以根据自己的实际情况来选择合适的数据隔离方案。