搶先一步
VMware 提供培訓和認證,助您加速進步。
瞭解更多Spring Boot 對 Testcontainers 的支援已經有一段時間了,而 Spring Boot 3.1 進一步改進了它。但首先,讓我們看看 Testcontainers 是什麼以及它通常如何使用。
Testcontainers 是一個開源框架,用於提供一次性、輕量級的資料庫、訊息代理、Web 瀏覽器或幾乎任何可以在 Docker 容器中執行的例項。
如果您以前使用過 Testcontainers,很可能是在整合測試中使用它們
@SpringBootTest
@Testcontainers
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 資料庫在 Testcontainer 內啟動,並使用 @DynamicPropertySource
配置 Spring Boot 以使用執行在容器中的 Neo4j 資料庫。
透過 Spring Boot 3.1,我們添加了兩個與 Testcontainers 相關的新功能。這兩個功能都是在 ConnectionDetails
抽象之上實現的,我們在另一篇部落格文章中重點介紹了它。如果您還沒有閱讀,請現在就去閱讀。這樣,本部落格文章的其餘部分將更有意義。
第一個功能使得使用 Testcontainers 進行整合測試更加容易。新的 @ServiceConnection
註解可以用於測試中的容器例項欄位
@SpringBootTest
@Testcontainers
class MyIntegrationTests {
@Container
@ServiceConnection
static Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:5");
@Test
void myTest() {
// ...
}
}
這取代了 @DynamicPropertySource
程式碼的需求,因此您只需將其刪除即可。
底層實現中,@ServiceConnection
會發現被註解的容器型別,併為其建立一個 ConnectionDetails
bean。在我們的示例中,該 bean 將是 Neo4jConnectionDetails
。Spring Boot 對 Neo4j 的自動配置會消費這個 bean,並配置驅動程式連線到在 Testcontainer 中執行的 Neo4j 伺服器。這適用於 Testcontainers 支援的許多不同容器型別。如果您使用 GenericContainer
,我們將檢視映象名稱來推斷容器型別。如果您使用的自定義映象名稱我們無法識別,您可以使用 @ServiceConnection
註解的 name
屬性來指明正確的方向。
使用 @ServiceConnection
註解容器欄位有幾個優點。首先,您需要編寫的程式碼更少。其次,整合測試和 Spring Boot 自動配置之間不再透過屬性進行“字串化”的型別耦合。第三,您無需查詢(或記住)屬性名稱。
我們認為這是一個非常巧妙的功能,足以成為升級到 Spring Boot 3.1 的理由。如果您還不信服,讓我們再向您展示另一個很棒的功能:開發時使用 Testcontainers。
大多數應用程式需要某種外部服務,例如 PostgreSQL 資料庫、Redis 伺服器或 Zipkin 後端。通常,這些服務是透過在編寫程式碼之前執行 readme 中的一些 docker run
命令來提供的,或者您可以使用 Docker Compose 之類的工具(Spring Boot 3.1 也為其添加了一些很酷的新功能)。
透過在開發時使用 Testcontainers,您的工具箱中又多了一個工具。為什麼您只應該將 Testcontainers 用於整合測試呢?從技術上講,沒有任何東西阻止您在生產程式碼中啟動 Testcontainers,然後設定屬性來連線到這些容器。即使在使用 3.1 之前的 Spring Boot 版本時,這也是可行的。
這種方法的缺點是您現在需要在編譯類路徑中包含 Testcontainers 依賴項,並且這個依賴項很可能也會包含在您的 fat JAR 中。使用 Spring Boot 3.1,有一個更好的方法:將 Testcontainers 依賴項留在 test
範圍內。您所需要做的就是在您的測試程式碼中建立一個新的 main
方法
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main).run(args);
}
}
這個測試 main
方法使用新的 SpringApplication.from
方法委託給您生產程式碼中的“實際” main 方法。
您現在可以建立一個 @TestConfiguration
來定義您在開發應用程式時所需的 Testcontainers 的 bean
@TestConfiguration(proxyBeanMethods = false)
class MyContainersConfiguration {
@Bean
@ServiceConnection
Neo4jContainer<?> neo4jContainer() {
return new Neo4jContainer<>("neo4j:5");
}
}
請注意,這個 bean 方法使用 @ServiceConnection
註解,以便 Spring Boot 自動建立與容器中執行服務的連線。此容器的生命週期由 Spring Boot 管理。我們在應用程式啟動時啟動容器,並在應用程式停止時將其關閉。
完成這些後,回到您的測試 main
方法,並將其指向新建立的 @TestConfiguration
public class TestMyApplication {
public static void main(String[] args) {
SpringApplication.from(MyApplication::main)
.with(MyContainersConfiguration.class)
.run(args);
}
}
現在,您可以從您的 IDE 啟動這個測試 main
方法,容器會自動啟動,並且 Spring Boot 會建立與它們的連線。您無需設定任何配置屬性,Spring Boot 會確保在您的應用程式停止時關閉容器。如果您更喜歡從終端執行應用程式,我們也考慮到了這一點。Gradle 和 Maven 的 Spring Boot 外掛學會了執行這個測試 main
方法。使用 Gradle,命令是 ./gradlew bootTestRun
,使用 Maven,命令是 ./mvnw spring-boot:test-run
。
需要注意的是,每次重新啟動應用程式時,容器都會關閉,並因此丟失資料。這可以透過兩種方式解決:第一種是使用 Spring Boot devtools,然後使用 @RestartScope
註解您的容器 bean 方法。當 devtools 重新啟動您的應用程式時,此類容器不會重新啟動。這意味著您每次更改應用程式中的內容時,都不必等待容器啟動,並且容器會保留其資料。
第二種方式是 Testcontainers 中的一個名為可重用容器的功能
@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {
@Bean
@ServiceConnection
public Neo4jContainer<?> neo4jContainer() {
return new Neo4jContainer<>("neo4j:5").withReuse(true);
}
}
當應用程式關閉時,此類容器不會停止。這是一個實驗性的 Testcontainers 功能,請自行承擔風險使用。
為了完整起見,這裡列出了我們目前支援的容器列表
CassandraContainer
CouchbaseContainer
ElasticsearchContainer
redis
或 openzipkin/zipkin
的 GenericContainer
JdbcDatabaseContainer
KafkaContainer
MongoDBContainer
MariaDBContainer
MSSQLServerContainer
MySQLContainer
Neo4jContainer
OracleContainer
PostgreSQLContainer
RabbitMQContainer
RedpandaContainer
我們希望您喜歡這些新功能,並希望它們能幫助您編寫出更出色的應用程式。請閱讀文件以開始使用,如果您發現任何問題或有進一步改進的建議,請聯絡我們!