7.9.4. 测试容器

Testcontainers库提供了一种管理 Docker 容器内运行的服务的方法。它与 JUnit 集成,允许您编写一个测试类,该测试类可以在任何测试运行之前启动容器。Testcontainers 对于编写与真实后端服务(例如 MySQL、MongoDB、Cassandra 等)通信的集成测试特别有用。

测试容器可以在 Spring Boot 测试中使用,如下所示:

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

}

这将在运行任何测试之前启动一个运行 Neo4j 的 docker 容器(如果 Docker 在本地运行)。在大多数情况下,您需要配置应用程序以连接到容器中运行的服务。

服务连接

服务连接是与任何远程服务的连接。Spring Boot 的自动配置可以使用服务连接的详细信息,并使用它们来建立与远程服务的连接。执行此操作时,连接详细信息优先于任何与连接相关的配置属性。

使用测试容器时,可以通过注释测试类中的容器字段来自动为容器中运行的服务创建连接详细信息。

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    @ServiceConnection
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

}

由于@ServiceConnection,上述配置允许应用程序中与 Neo4j 相关的 bean 与 Testcontainers 管理的 Docker 容器内运行的 Neo4j 进行通信。这是通过自动定义一个Neo4jConnectionDetailsbean 来完成的,然后由 Neo4j 自动配置使用该 bean,覆盖任何与连接相关的配置属性。

您需要将该spring-boot-testcontainers模块添加为测试依赖项,以便将服务连接与测试容器一起使用。

服务连接注解由注册到spring.factoriesContainerConnectionDetailsFactory 类处理。 ContainerConnectionDetailsFactory 可以基于特定的 Container 子类或 Docker 映像名称创建 ConnectionDetailsbean。

spring-boot-testcontainersjar中提供了以下服务连接工厂:

连接详情

匹配于

ActiveMQConnectionDetails

名为“symptoma/activemq”的容器

CassandraConnectionDetails

容器类型CassandraContainer

CouchbaseConnectionDetails

容器类型CouchbaseContainer

ElasticsearchConnectionDetails

容器类型ElasticsearchContainer

FlywayConnectionDetails

容器类型JdbcDatabaseContainer

JdbcConnectionDetails

容器类型JdbcDatabaseContainer

KafkaConnectionDetails

类型KafkaContainerRedpandaContainer的容器

LiquibaseConnectionDetails

容器类型JdbcDatabaseContainer

MongoConnectionDetails

容器类型MongoDBContainer

Neo4jConnectionDetails

容器类型Neo4jContainer

OtlpMetricsConnectionDetails

名为“otel/opentelemetry-collector-contrib”的容器

OtlpTracingConnectionDetails

名为“otel/opentelemetry-collector-contrib”的容器

PulsarConnectionDetails

容器类型PulsarContainer

R2dbcConnectionDetails

类型为MariaDBContainerMSSQLServerContainerMySQLContainerOracleContainerPostgreSQLContainer的容器

RabbitConnectionDetails

容器类型RabbitMQContainer

RedisConnectionDetails

名为“redis”的容器

ZipkinConnectionDetails

名为“openzipkin/zipkin”的容器

默认情况下,将为给定的Container创建所有适用的连接详细信息 bean 。例如, PostgreSQLContainer将创建JdbcConnectionDetailsR2dbcConnectionDetails

如果您只想创建适用类型的子集,则可以使用type的属性@ServiceConnection

默认情况下Container.getDockerImageName()用于获取用于查找连接详细信息的名称。只要 Spring Boot 能够获取Container 的实例,这种情况就有效,就像使用上面示例中的static字段时的情况一样。

如果您使用@Bean方法,Spring Boot 将不会调用 bean 方法来获取 Docker 映像名称,因为这会导致急切的初始化问题。相反,bean 方法的返回类型用于找出应使用哪个连接详细信息。只要您使用类型化容器(例如Neo4jContainerRabbitMQContainer) ,此方法就有效。如果您正在使用(例如 Redis),GenericContainer将停止工作,如以下示例所示:

@TestConfiguration(proxyBeanMethods = false)
public class MyRedisConfiguration {

    @Bean
    @ServiceConnection(name = "redis")
    public GenericContainer<?> redisContainer() {
        return new GenericContainer<>("redis:7");
    }

}

Spring Boot 无法判断GenericContainer使用的是哪个容器映像,因此必须使用@ServiceConnectionname 属性来提供该提示。

您还可以使用@ServiceConnectionname属性来覆盖将使用的连接详细信息,例如在使用自定义图像时。如果您使用 Docker 映像registry.mycompany.com/mirror/myredis,则需要@ServiceConnection(name="redis")确保RedisConnectionDetails已创建。

动态属性

服务连接的一个稍微详细但也更灵活的替代方案是@DynamicPropertySource。静态@DynamicPropertySource方法允许向 Spring 环境添加动态属性值。

@Testcontainers
@SpringBootTest
class MyIntegrationTests {

    @Container
    static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");

    @Test
    void myTest() {
        // ...
    }

    @DynamicPropertySource
    static void neo4jProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
    }

}

上述配置允许应用程序中与 Neo4j 相关的 bean 与 Testcontainers 管理的 Docker 容器内运行的 Neo4j 进行通信。

最后更新于