このバージョンはまだ開発中であり、まだ安定しているとは見なされていません。最新の安定バージョンについては、Spring Boot 3.4.4 を使用してください! |
Testcontainers
Testcontainers (英語) ライブラリは、Docker コンテナー内で実行されるサービスを管理する方法を提供します。JUnit と統合されているため、テストを実行する前にコンテナーを起動できるテストクラスを作成できます。Testcontainers は、MySQL、MongoDB、Cassandra などの実際のバックエンドサービスと通信する統合テストを作成する場合に特に役立ちます。
テストコンテナーは、Spring Boot テストで次のように使用できます。
Java
Kotlin
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Container
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Test
fun myTest() {
// ...
}
companion object {
@Container
@JvmStatic
val neo4j = Neo4jContainer("neo4j:5");
}
}
これにより、テストが実行される前に、Neo4j を実行する docker コンテナーが起動されます (Docker がローカルで実行されている場合)。ほとんどの場合、コンテナーで実行されているサービスに接続するようにアプリケーションを構成する必要があります。
サービス接続
サービス接続は、任意の リモートサービスへの接続です。Spring Boot の自動構成は、サービス接続の詳細を消費し、使用して リモートサービスへの接続を確立できます。その場合、接続の詳細は、接続関連の構成プロパティよりも優先されます。
Testcontainers を使用すると、テストクラスのコンテナーフィールドにアノテーションを付けることで、コンテナーで実行されているサービスの接続の詳細を自動的に作成できます。
Java
Kotlin
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Container
@ServiceConnection
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Test
fun myTest() {
// ...
}
companion object {
@Container
@ServiceConnection
@JvmStatic
val neo4j = Neo4jContainer("neo4j:5");
}
}
@ServiceConnection
(Javadoc) のおかげで、上記の構成により、アプリケーション内の Neo4j 関連の Bean は、Testcontainers が管理する Docker コンテナー内で実行されている Neo4j と通信できるようになります。これは、Neo4jConnectionDetails
(Javadoc) Bean を自動的に定義することによって行われ、これは Neo4j の自動構成によって使用され、接続関連の構成プロパティが上書きされます。
Testcontainers とのサービス接続を使用するには、spring-boot-testcontainers モジュールをテストの依存関係として追加する必要があります。 |
サービス接続アノテーションは、spring.factories
に登録された ContainerConnectionDetailsFactory
(Javadoc) クラスによって処理されます。ContainerConnectionDetailsFactory
(Javadoc) は、特定の Container
(英語) サブクラスまたは Docker イメージ名に基づいて、ConnectionDetails
(Javadoc) Bean を作成できます。
spring-boot-testcontainers
jar では、次のサービス接続ファクトリが提供されます。
接続詳細 | 一致 |
---|---|
"symptoma/activemq" または | |
| |
| |
| |
| |
| |
| |
| |
"osixia/openldap" という名前のコンテナーまたは型 | |
| |
| |
| |
"otel/opentelemetry-collector-contrib" という名前のコンテナーまたは型 | |
"otel/opentelemetry-collector-contrib" という名前のコンテナーまたは型 | |
"otel/opentelemetry-collector-contrib" という名前のコンテナーまたは型 | |
| |
型 | |
| |
型 | |
"openzipkin/zipkin" という名前のコンテナー |
デフォルトでは、特定の 適用可能な型のサブセットのみを作成する場合は、 |
デフォルトでは、接続の詳細を見つけるために使用される名前を取得するために Container.getDockerImageName().getRepository()
が使用されます。Docker イメージ名のリポジトリ部分は、レジストリとバージョンを無視します。これは、Spring Boot が Container
(英語) のインスタンスを取得できる限り機能します。これは、上記の例のように static
フィールドを使用する場合に当てはまります。
@Bean
(Javadoc) メソッドを使用している場合、Spring Boot は Bean メソッドを呼び出して Docker イメージ名を取得しません。これは、早期初期化の問題が発生するためです。代わりに、Bean メソッドの戻り値の型を使用して、どの接続詳細を使用する必要があるかを判断します。これは、Neo4jContainer
(英語) や RabbitMQContainer
(英語) などの型指定されたコンテナーを使用している限り機能します。GenericContainer
(英語) を使用している場合、たとえば次の例に示すように Redis を使用している場合は機能しなくなります。
Java
Kotlin
import org.testcontainers.containers.GenericContainer;
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 MyRedisConfiguration {
@Bean
@ServiceConnection(name = "redis")
public GenericContainer<?> redisContainer() {
return new GenericContainer<>("redis:7");
}
}
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.testcontainers.service.connection.ServiceConnection
import org.springframework.context.annotation.Bean
import org.testcontainers.containers.GenericContainer
@TestConfiguration(proxyBeanMethods = false)
class MyRedisConfiguration {
@Bean
@ServiceConnection(name = "redis")
fun redisContainer(): GenericContainer<*> {
return GenericContainer("redis:7")
}
}
Spring Boot は、GenericContainer
(英語) からどのコンテナーイメージが使用されているかを判断できないため、そのヒントを提供するには、@ServiceConnection
(Javadoc) の name
属性を使用する必要があります。
また、カスタムイメージを使用する場合など、@ServiceConnection
(Javadoc) の name
属性を使用して、使用する接続の詳細をオーバーライドすることもできます。Docker イメージ registry.mycompany.com/mirror/myredis
を使用している場合は、RedisConnectionDetails
(Javadoc) が確実に作成されるように @ServiceConnection(name="redis")
を使用します。
サービス接続での SSL
サポートされているコンテナーで @Ssl
(Javadoc) 、@JksKeyStore
(Javadoc) 、@JksTrustStore
(Javadoc) 、@PemKeyStore
(Javadoc) 、@PemTrustStore
(Javadoc) アノテーションを使用して、そのサービス接続の SSL サポートを有効にすることができます。テストコンテナー内で実行されているサービスで SSL を有効にする必要があることに注意してください。アノテーションは、アプリケーションのクライアント側でのみ SSL を構成します。
import com.redis.testcontainers.RedisContainer;
import org.junit.jupiter.api.Test;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.testcontainers.service.connection.PemKeyStore;
import org.springframework.boot.testcontainers.service.connection.PemTrustStore;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.data.redis.core.RedisOperations;
@Testcontainers
@SpringBootTest
class MyRedisWithSslIntegrationTests {
@Container
@ServiceConnection
@PemKeyStore(certificate = "classpath:client.crt", privateKey = "classpath:client.key")
@PemTrustStore("classpath:ca.crt")
static RedisContainer redis = new SecureRedisContainer("redis:latest");
@Autowired
private RedisOperations<Object, Object> operations;
@Test
void testRedis() {
// ...
}
}
上記のコードでは、@PemKeyStore
(Javadoc) アノテーションを使用してクライアント証明書とキーをキーストアに読み込み、@PemTrustStore
(Javadoc) アノテーションを使用して CA 証明書をトラストストアに読み込みます。これにより、クライアントがサーバーに対して認証され、トラストストアの CA 証明書によって、サーバー証明書が有効で信頼できることが確認されます。
この例の SecureRedisContainer
は、証明書を適切な場所にコピーし、SSL を有効にするコマンドラインパラメーターを使用して redis-server
を呼び出す RedisContainer
のカスタムサブクラスです。
SSL アノテーションは、次のサービス接続でサポートされています。
Cassandra
Couchbase
Elasticsearch
Kafka
MongoDB
RabbitMQ
Redis
ElasticsearchContainer
は、サーバー側 SSL の自動検出もサポートしています。この機能を使用するには、次の例に示すように、コンテナーに @Ssl
(Javadoc) のアノテーションを付けます。そうすると、Spring Boot がクライアント側の SSL 構成を処理します。
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.elasticsearch.DataElasticsearchTest;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.boot.testcontainers.service.connection.Ssl;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
@Testcontainers
@DataElasticsearchTest
class MyElasticsearchWithSslIntegrationTests {
@Ssl
@Container
@ServiceConnection
static ElasticsearchContainer elasticsearch = new ElasticsearchContainer(
"docker.elastic.co/elasticsearch/elasticsearch:8.17.2");
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Test
void testElasticsearch() {
// ...
}
}
動的プロパティ
サービス接続のやや冗長ですが、より柔軟な代替手段は @DynamicPropertySource
(Javadoc) です。静的 @DynamicPropertySource
(Javadoc) メソッドを使用すると、動的なプロパティ値を Spring 環境に追加できます。
Java
Kotlin
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
@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);
}
}
import org.junit.jupiter.api.Test
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.DynamicPropertyRegistry
import org.springframework.test.context.DynamicPropertySource
import org.testcontainers.containers.Neo4jContainer
import org.testcontainers.junit.jupiter.Container
import org.testcontainers.junit.jupiter.Testcontainers
@Testcontainers
@SpringBootTest
class MyIntegrationTests {
@Test
fun myTest() {
// ...
}
companion object {
@Container
@JvmStatic
val neo4j = Neo4jContainer("neo4j:5");
@DynamicPropertySource
@JvmStatic
fun neo4jProperties(registry: DynamicPropertyRegistry) {
registry.add("spring.neo4j.uri") { neo4j.boltUrl }
}
}
}
上記の構成により、アプリケーション内の Neo4j 関連の Bean が、Testcontainers が管理する Docker コンテナー内で実行されている Neo4j と通信できるようになります。