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
のおかげで、上記の構成により、アプリケーション内の Neo4j 関連の Bean は、Testcontainers が管理する Docker コンテナー内で実行されている Neo4j と通信できます。これは、Neo4j 自動構成によって使用される Neo4jConnectionDetails
Bean を自動的に定義し、接続関連の構成プロパティをオーバーライドすることによって行われます。
Testcontainers とのサービス接続を使用するには、spring-boot-testcontainers モジュールをテストの依存関係として追加する必要があります。 |
サービス接続アノテーションは、spring.factories
に登録された ContainerConnectionDetailsFactory
クラスによって処理されます。ContainerConnectionDetailsFactory
は、特定の Container
サブクラス、または Docker イメージ名に基づいて ConnectionDetails
Bean を作成できます。
spring-boot-testcontainers
jar では、次のサービス接続ファクトリが提供されます。
接続詳細 | 一致 |
---|---|
| "symptoma/activemq" または |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| "otel/opentelemetry-collector-contrib" という名前のコンテナー |
| "otel/opentelemetry-collector-contrib" という名前のコンテナー |
|
|
|
|
|
|
| "redis" という名前のコンテナー |
| "openzipkin/zipkin" という名前のコンテナー |
デフォルトでは、該当するすべての接続詳細 Bean が特定の 該当する型のサブセットのみを作成する場合は、 |
デフォルトでは、接続の詳細を見つけるために使用される名前を取得するために Container.getDockerImageName().getRepository()
が使用されます。Docker イメージ名のリポジトリ部分は、レジストリとバージョンを無視します。これは、Spring Boot が Container
のインスタンスを取得できる限り機能します。これは、上記の例のように static
フィールドを使用する場合に当てはまります。
@Bean
メソッドを使用している場合、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
の name
属性を使用する必要があります。
@ServiceConnection
の name
属性を使用して、カスタムイメージを使用する場合などに、どの接続詳細が使用されるかをオーバーライドすることもできます。Docker イメージ registry.mycompany.com/mirror/myredis
を使用している場合は、@ServiceConnection(name="redis")
を使用して RedisConnectionDetails
が確実に作成されるようにします。
動的プロパティ
@DynamicPropertySource
は、サービス接続に代わる、やや冗長ですが、より柔軟な代替手段です。静的 @DynamicPropertySource
メソッドを使用すると、動的プロパティ値を 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 と通信できるようになります。