Testcontainers
Testcontainers 函式庫提供一種管理在 Docker 容器內運行的服務的方法。它與 JUnit 整合,讓您可以編寫一個測試類別,在任何測試運行之前啟動容器。Testcontainers 對於編寫與真實後端服務(如 MySQL、MongoDB、Cassandra 等)對話的整合測試特別有用。
Testcontainers 可以在 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 相關的 beans 與在 Testcontainers 管理的 Docker 容器內運行的 Neo4j 通訊。這是通過自動定義一個 Neo4jConnectionDetails
bean 來完成的,該 bean 然後被 Neo4j 自動組態使用,覆蓋任何與連線相關的組態屬性。
您需要新增 spring-boot-testcontainers 模組作為測試依賴項,以便將服務連線與 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" 的容器 |
預設情況下,將為給定的 如果您只想建立適用類型的子集,可以使用 |
預設情況下,Container.getDockerImageName().getRepository()
用於取得用於查找連線詳細資訊的名稱。Docker 映像檔名稱的 repository 部分忽略任何 registry 和版本。只要 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 相關的 beans 與在 Testcontainers 管理的 Docker 容器內運行的 Neo4j 通訊。