如何使用Testcontainers进行数据访问逻辑的测试
首先
我使用Testcontainers编写了一个测试代码,用于对MySQL的CRUD数据访问逻辑进行测试。在本文中,我摘录了一些示例代码,但完整的源代码可以在GitHub存储库中查看。
Testcontainers是什么?
在公式参考资料中,以下这样进行了解释。
Testcontainers是一个支持JUnit测试的Java库,它提供了轻量级的、一次性的常见数据库、Selenium网页浏览器或任何可以在Docker容器中运行的实例。
换言之,在进行涉及外部访问的测试,例如与数据库有关的测试时,可以通过在测试运行时仅启用的Docker容器来代替访问目标,从而获得以下优势。
-
- アクセス先を開発用ローカルマシン内に立ち上げたり、ローカルネットワーク内に立ち上げたりする必要が無くなる
-
- テストコードや設定ファイルを共有するだけで同じテスト環境を共有できる
-
- テスト実施時はアクセス先が毎回同じ状態であることが保証される
- テスト終了後はコンテナが破棄され、テストの影響が残らない
本次我们将通过使用Testcontainers连接到由单体测试代码生成的Docker容器内的MySQL,从而能够在不准备实际的MySQL数据库的情况下进行测试。
如果使用JDBC,这里解释的内容大部分适用于除了MySQL以外的其他数据库。此外,Testcontainers也支持许多Docker镜像,不仅限于数据库。可以在官方参考文档的“Modules”中查看可用镜像列表。
环境
-
- Java
-
- Junit5
-
- Spring Boot
-
- MyBatis
-
- Maven
- Windows10(※Testcontainers実行時はDocker Desktopを起動しておく必要があります)
依赖关系
为了在JUnit5中使用Testcontainers,需要将org.testcontainers:junit-jupiter作为依赖项添加到中;为了在Testcontainers中使用MySQL镜像,还需要将org.testcontainers:mysql作为依赖项添加到中。此外,即使将使用的数据库镜像添加到依赖项中,该数据库的JDBC驱动程序仍然需要在类路径上单独存在,因此还需要将MySQL的JDBC驱动程序也添加到中。
<dependencies>
...
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>1.16.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<version>1.16.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<!-- Spring Boot利用のためバージョンは省略 -->
</dependency>
...
</dependencies>
在公式参考文档中建议将Testcontainers的BOM添加到中,而不是在每个依赖关系中单独显式地指定。
<dependencyManagement>
<dependencies>
...
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>testcontainers-bom</artifactId>
<version>1.16.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
...
</dependencies>
</dependencyManagement>
<dependencies>
...
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<!-- <version>1.16.2</version> BOM利用時は省略可-->
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>mysql</artifactId>
<!-- <version>1.16.2</version> BOM利用時は省略可-->
<scope>test</scope>
</dependency>
...
</dependencies>
通过添加BOM,每个Testcontainers依赖关系的版本将自动与BOM的版本对应。
创建容器的方式
在使用测试代码创建可以访问的MySQL容器方面,Testcontainers官方参考文档提供了以下两种方法。
1. 使用Testcontainers的JDBC URL来指示生成容器的方法
2. 使用数据库容器对象在测试代码中明确地生成容器的方法
在公式参考文献中,首先建议考虑使用Testcontainers用的JDBC URL的方法,如果该方法受到约束无法采用或者需要对数据库容器进行更详细的配置,则推荐采用2.Database container objects的方法。
在本次中,我们选择采用了使用Testcontainers用的JDBC URL的方法。
另外,詳細內容稍後提及,但使用Testcontainers JDBC URL 的方法不需要在測試代碼中編寫生成容器的處理程序,只需將Testcontainers JDBC URL 更改為實際連接的 DB JDBC URL,即可切換到使用實際 DB 的測試。
Testcontainers使用JDBC URL的格式。
只需要一个选项:
通过以下步骤修改实际的 JDBC URL,可以将其转换为 Testcontainers 格式的 JDBC URL,并且在测试执行时会生成指定镜像的 DB 容器。在本次使用 Spring Boot 的示例中,如果在 spring.datasource.url 属性中指定 Testcontainers 用的 JDBC URL,则 Testcontainers 将被启用。
-
- 在jdbc:后面插入tc:
- 将驱动程序名称替换为Docker镜像名称:标签名
- jdbc:mysql://localhost:3306/databasename
+ jdbc:tc:mysql:8.0://localhost:3306/databasename
(「tc」を挿入し、「mysql」というドライバ名を「mysql:8.0」というDockerイメージ名に置換)
另外,对于Testcontainers,JDBC URL中的主机名:端口号/数据库名将被忽略,因此可以最终简化为以下方式。
- jdbc:tc:mysql:8.0://localhost:3306/databasename
+ jdbc:tc:mysql:8.0:///
(「ホスト名:ポート番号/データベース名」を除去)
我们将这种缩写形式称为无主机URI。
jdbc:tc:[Dockerイメージ名]:[タグ名]///
建议在使用Testcontainers进行测试时,为测试用的JDBC URL使用无主机的URI,这样当查看JDBC URL时可以立即知道正在使用Testcontainers。
无论JDBC URL是否缩短,Testcontainers生成的容器的数据库名称、用户名和密码都固定为”test”。如果您想要更改这些,请使用上述的**数据库容器对象**来生成容器。
在公式的参考资料中的说明中,
公式: 方程式
リファレンス: 参考资料
内: 内部的
解説: 解释
可以翻译为:在公式的参考资料中的说明中,
请注意,主机名、端口和数据库名称将被忽略。
尽管有明确的说明,但在示例中仅指定了数据库名称的JDBC URL(如jdbc:mysql:8.0:///databasename)。然而,2022/02目前指定的数据库名称不会反映在生成的容器中。在GitHub的问题跟帖中,已经讨论了这个问题。
在中国是如何选择选项的
Testcontainers允许使用JDBC URL指定选项,可以以查询参数的形式进行设置。如果需要指定多个选项,可以像查询参数一样用&进行连接。
有多种选项可供选择,但在这里我们将介绍TC_INITSCRIPT选项。有关其他选项,请参考官方参考文档。DB镜像还可能有特定的选项。
初始化脚本
指定されたSQLファイルのパスを追加します。
TC_INITSCRIPT=[初期化用SQLファイルのパス]
请在Classpath中添加。请使用“绝对路径从Classpath根目录开始”的路径。
jdbc:tc:mysql:8.0:///?TC_INITSCRIPT=path/to/ddl.sql
(DBコンテナ生成後に、「ddl.sql」というSQLファイルを実行させる場合の例)
编写测试代码的方法
我将解释如何编写使用Testcontainers库生成的DB容器来进行测试的代码。
首先,我会提供一个示例测试代码,并解释每个关键点。
@Testcontainers // (1)
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE) // (2)
@MybatisTest // (3)
@Sql("classpath:path/to/testdata.sql") // (4)
class UserDaoTest {
@Autowired
private UserDao dao;
@Test
void testUserDao() {
// (5)
}
}
(1) @Testcontainers 是一个用于在测试类中声明使用 Testcontainers 生成的 Docker 容器的注解。通过为测试类添加此注解,测试执行前会基于 JDBC URL 生成和初始化 DB 容器。
@Testcontainers(disabledWithoutDocker = true)
如果将disableWithoutDocker参数设置为true,则在测试运行时如果无法使用Docker,测试将被跳过。(如果使用Windows PC,在没有启动Docker Desktop的情况下运行测试,可以确认测试将被跳过。)
(2) @AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
这是一个用于禁用默认启用的Spring Boot内置测试数据库的注释。除了添加此注释外,还可以通过将spring.test.database.replace属性设置为none来实现相同的效果。
(3) @MybatisTest
由于本次使用MyBatis作为O/R映射器,我们在测试代码中使用了@MyBatisTest注解,以仅使与MyBatis相关的AutoConfigure类和Mapper类的Bean有效。
有关@MyBatisTest的详细信息,请参考此文章。
(4)@Sql
这是一个注解,可以在每个测试方法执行之前执行指定的SQL文件。它用于向DB容器中插入测试数据。
虽然可以使用上述的TC_INITSCRIPT选项来初始化带有SQL文件的DB容器,但是该选项只能指定一个SQL文件。因此,需要在一个SQL文件中编写DDL和插入测试数据。
如果希望将DDL和插入测试数据管理在不同的SQL文件中,或者根据测试用例切换要插入的测试数据,则可以使用@Sql注解来插入测试数据,就像本示例一样。此外,也可以与Testcontainers一起使用DBUnit等工具。
(5) 测试方法的实现
在每个测试方法中,您可以像使用实际的DB一样编写测试代码,而不需要意识到Testcontainers的使用。
属性文件的编写方法
由于本示例使用了Spring Boot,因此我们也会解释与Testcontainers相关的属性文件的编写方法。
spring.datasource.url=${DATASOURCE:jdbc:tc:mysql:8.0:///?TC_INITSCRIPT=path/to/ddl.sql}
spring.datasource.username=${DATASOURCE_USER:}
spring.datasource.password=${DATASOURCE_PASSWORD:}
spring.test.database.replace=none
spring.datasource.url
Testcontainers使用JDBC URL进行指定。
在这个示例中,使用${环境变量:默认值}的格式来指定属性值,如果环境变量DATASOURCE的值已设置,则使用该值作为JDBC URL,否则使用Testcontainers的JDBC URL。
如果JDBC URL不是Testcontainers的格式,即使测试类已经使用了上述的@Testcontainers注解,也不会生成数据库容器。因此,在例如预发布环境中,通过设置环境变量来进行实际数据库测试,在本地环境中可以进行基于数据库容器的测试,而无需修改测试代码或准备多个测试代码,就可以实现这样的需求。
spring.datasource.username 和 spring.datasource.password是以${環境変数:デフォルト値}的格式表示的,但是没有指定默认值。如前所述,当使用Testcontainers用JDBC URL时,用户名和密码是固定为test的,无法指定,因此要通过指定属性值的方式来设置。
spring.test.database.replace的作用是替换@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)注解,在使用属性文件进行配置的情况下。
考试执行
与常规测试一样,您可以使用Eclipse或Maven来运行它。
以下是运行测试时生成的日志。(如果您是在Testcontainers中首次使用指定的Docker镜像,则可能需要几分钟以上的时间。)
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.6.2)
2022-01-31 10:55:26.500 INFO 16468 --- [ main] com.example.UserDaoTest : Starting UserDaoTest using Java 17.0.1 on with PID 16468 (started by)
2022-01-31 10:55:26.502 INFO 16468 --- [ main] com.example.UserDaoTest : No active profile set, falling back to default profiles: default
2022-01-31 10:55:27.819 INFO 16468 --- [ main] com.example.UserDaoTest : Started UserDaoTest in 1.891 seconds (JVM running for 3.261)
2022-01-31 10:55:27.868 INFO 16468 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2022-01-31 10:55:28.130 INFO 16468 --- [ main] o.t.d.DockerClientProviderStrategy : Loaded org.testcontainers.dockerclient.NpipeSocketClientProviderStrategy from ~/.testcontainers.properties, will try it first
2022-01-31 10:55:28.723 INFO 16468 --- [ main] o.t.d.DockerClientProviderStrategy : Found Docker environment with local Npipe socket (npipe:////./pipe/docker_engine)
2022-01-31 10:55:28.725 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Docker host IP address is localhost
2022-01-31 10:55:28.779 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Connected to docker:
Server Version: 20.10.11
API Version: 1.41
Operating System: Docker Desktop
Total Memory: 4711 MB
2022-01-31 10:55:28.784 INFO 16468 --- [ main] o.t.utility.ImageNameSubstitutor : Image name substitution will be performed by: DefaultImageNameSubstitutor (composite of 'ConfigurationFileImageNameSubstitutor' and 'PrefixingImageNameSubstitutor')
2022-01-31 10:55:29.215 INFO 16468 --- [ main] o.t.utility.RegistryAuthLocator : Credential helper/store (docker-credential-desktop) does not have credentials for index.docker.io
2022-01-31 10:55:32.569 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Ryuk started - will monitor and terminate Testcontainers containers on JVM exit
2022-01-31 10:55:32.570 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : Checking the system...
2022-01-31 10:55:32.571 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : ✔︎ Docker server version should be at least 1.6.0
2022-01-31 10:55:32.706 INFO 16468 --- [ main] org.testcontainers.DockerClientFactory : ✔︎ Docker environment should have more than 2GB free disk space
2022-01-31 10:55:32.725 INFO 16468 --- [ main] ? [mysql:8.0] : Creating container for image: mysql:8.0
2022-01-31 10:55:32.879 INFO 16468 --- [ main] ? [mysql:8.0] : Starting container with ID: 466df4de50fe211466427c0c56d673ba8ebb9b4edbf8f124eb654560614bb8a2
2022-01-31 10:55:33.253 INFO 16468 --- [ main] ? [mysql:8.0] : Container mysql:8.0 is starting: 466df4de50fe211466427c0c56d673ba8ebb9b4edbf8f124eb654560614bb8a2
2022-01-31 10:55:33.325 INFO 16468 --- [ main] ? [mysql:8.0] : Waiting for database connection to become available at jdbc:mysql://localhost:62119/test using query 'SELECT 1'
2022-01-31 10:55:48.318 INFO 16468 --- [ main] ? [mysql:8.0] : Container is started (JDBC URL: jdbc:mysql://localhost:62119/test)
2022-01-31 10:55:48.318 INFO 16468 --- [ main] ? [mysql:8.0] : Container mysql:8.0 started in PT15.6056995S
2022-01-31 10:55:48.353 INFO 16468 --- [ main] org.testcontainers.ext.ScriptUtils : Executing database script from META-INF/mysql/ddl.sql
2022-01-31 10:55:48.406 INFO 16468 --- [ main] org.testcontainers.ext.ScriptUtils : Executed database script from META-INF/mysql/ddl.sql in 52 ms.
2022-01-31 10:55:48.420 INFO 16468 --- [ main] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2022-01-31 10:55:48.430 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@cd1e646, testMethod = testDelete@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.jdbc.support.JdbcTransactionManager@73608eb0]; rollback [true]
2022-01-31 10:55:49.394 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@cd1e646, testMethod = testDelete@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
2022-01-31 10:55:49.411 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@266da047, testMethod = testSelect@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.jdbc.support.JdbcTransactionManager@73608eb0]; rollback [true]
2022-01-31 10:55:49.456 INFO 16468 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@3576ddc2 testClass = UserDaoTest, testInstance = com.example.UserDaoTest@266da047, testMethod = testSelect@UserDaoTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@35b74c5c testClass = UserDaoTest, locations = '{}', classes = '{class com.example.DemoApplication}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.mybatis.spring.boot.test.autoconfigure.MybatisTestContextBootstrapper=true}', contextCustomizers = set[[ImportsContextCustomizer@2e570ded key = [org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration, org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration, org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration, org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration, org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, org.springframework.boot.autoconfigure.sql.init.SqlInitializationAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisLanguageDriverAutoConfiguration, org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration, org.springframework.boot.test.autoconfigure.jdbc.TestDatabaseAutoConfiguration]], org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@61001b64, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@26e356f0, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.autoconfigure.OverrideAutoConfigurationContextCustomizerFactory$DisableAutoConfigurationContextCustomizer@272113c4, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@3f6f6701, org.springframework.boot.test.autoconfigure.filter.TypeExcludeFiltersContextCustomizer@351584c0, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@9647a2c9, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@13e344d, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@0], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
2022-01-31 10:55:49.468 INFO 16468 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated...
2022-01-31 10:55:50.017 INFO 16468 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
请阅读以下内容,只需要一个选择。
-
- https://www.testcontainers.org/
-
- https://b1a9idps.com/posts/test-containers/
- https://zenn.dev/kentama/articles/aa7bbe728845da
如果您有任何意见、批评或建议,请在评论中提供,谢谢。