本文为官方文档直译版本。原文链接
除了在集成测试中使用 Testcontainers 外,在开发过程中也可以使用它们。接下来的章节将详细介绍这一点。
这种方法允许开发人员为应用程序所依赖的服务快速启动容器,无需手动配置数据库服务器等。以这种方式使用 Testcontainers 所提供的功能与 Docker Compose 类似,只是容器配置使用的是 Java 而不是 YAML。
要在开发时使用 Testcontainers,您需要使用 "test "类路径而不是 "main "来启动应用程序。这将允许您访问所有已声明的测试依赖项,并为您提供一个编写测试配置的自然位置。
要创建应用程序的测试启动版本,应在 src/test
目录下创建一个 “Application” 类。例如,如果您的主应用程序在 src/main/java/com/example/MyApplication.java
中,则应创建 src/test/java/com/example/TestMyApplication.java
TestMyApplication
类可使用 SpringApplication.from(...)
方法启动真实应用程序:
import org.springframework.boot.SpringApplication;
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main).run(args);
}
}
您还需要定义要与应用程序一起启动的容器实例。为此,您需要确保已将 spring-boot-testcontainers
模块添加为测试依赖关系。添加完成后,您就可以创建一个 @TestConfiguration
类,为要启动的容器声明 @Bean
方法。
您还可以用 @ServiceConnection
对 @Bean
方法进行注解,以创建 ConnectionDetails
Bean。有关支持技术的详细信息,请参阅服务连接部分。
典型的 Testcontainers 配置如下所示:
import org.testcontainers.containers.Neo4jContainer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
@ServiceConnection
public Neo4jContainer<?> neo4jContainer() {
return new Neo4jContainer<>("neo4j:5");
}
}
容器 Bean 的生命周期由 Spring Boot 自动管理。容器将自动启动和停止。
您可以使用
spring.testcontainers.beans.startup
属性来更改容器的启动方式。默认情况下使用顺序启动,但如果希望并行启动多个容器,也可以选择并行启动。
定义好测试配置后,就可以使用 with(...)
方法将其附加到测试启动器:
import org.springframework.boot.SpringApplication;
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main).with(MyContainersConfiguration.class).run(args);
}
}
现在,您可以像启动普通 Java 主方法应用程序一样启动 TestMyApplication
,以启动应用程序及其运行所需的容器。
您可以使用 Maven 任务
spring-boot:test-run
或 Gradle 任务bootTestRun
从命令行执行此操作。
如果您想在开发时从容器 @Bean
方法中贡献动态属性,可以通过注入 DynamicPropertyRegistry
来实现。其工作方式与您可以在测试中使用的 @DynamicPropertySource
注解类似。它允许您添加在容器启动后可用的属性。
典型的配置如下:
import org.testcontainers.containers.MongoDBContainer;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.test.context.DynamicPropertyRegistry;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
public MongoDBContainer mongoDbContainer(DynamicPropertyRegistry properties) {
MongoDBContainer container = new MongoDBContainer("mongo:5.0");
properties.add("spring.data.mongodb.host", container::getHost);
properties.add("spring.data.mongodb.port", container::getFirstMappedPort);
return container;
}
}
建议尽可能使用
@ServiceConnection
,不过,对于尚未支持@ServiceConnection
的技术来说,动态属性可能是一种有用的备用方法。
使用 Testcontainers 时的一种常见模式是将 Container
实例声明为静态字段。这些字段通常直接在测试类中定义。它们也可以在父类或测试实现的接口上声明。
例如,下面的 MyContainers
接口声明了 mongo
和 neo4j
容器:
import org.testcontainers.containers.MongoDBContainer;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
public interface MyContainers {
@Container
@ServiceConnection
MongoDBContainer mongoContainer = new MongoDBContainer("mongo:5.0");
@Container
@ServiceConnection
Neo4jContainer<?> neo4jContainer = new Neo4jContainer<>("neo4j:5");
}
如果您已经有了以这种方式定义的容器,或者您只是喜欢这种风格,您可以导入这些声明类,而不是将容器定义为 @Bean
方法。为此,请在测试配置类中添加 @ImportTestcontainers
注解:
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.context.ImportTestcontainers;
@TestConfiguration(proxyBeanMethods = false)
@ImportTestcontainers(MyContainers.class)
public class MyContainersConfiguration {
}
如果您不打算使用服务连接功能,而是想使用
@DynamicPropertySource
,请从容器字段中删除@ServiceConnection
注解。您还可以在声明类中添加@DynamicPropertySource
注解方法。
使用 devtools 时,您可以用 @RestartScope
对 bean 和 bean 方法进行注解。当 devtools 重新启动应用程序时,这些 Bean 将不会被重新创建。这对 Testcontainer Container
Bean 尤其有用,因为它们会在应用程序重启时保持状态。
import org.testcontainers.containers.MongoDBContainer;
import org.springframework.boot.devtools.restart.RestartScope;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
@RestartScope
@ServiceConnection
public MongoDBContainer mongoDbContainer() {
return new MongoDBContainer("mongo:5.0");
}
}
如果您使用 Gradle 并希望使用此功能,则需要将
spring-boot-devtools
依赖关系的配置从 "developmentOnly
"更改为 “testImplementation
”。如果默认作用域为 “developmentOnly
”,BootTestRun
任务将无法捕获代码中的更改,因为 devtools 并未激活。