Spring Boot 3.1中改進的Testcontainers支援

工程 | 莫里茨·哈爾布里特 | 2023年6月23日 | ...

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。

開發時的 Testcontainers

大多數應用程式都需要某種外部服務,例如 PostgreSQL 資料庫、Redis 伺服器或 Zipkin 後端。通常,這些服務是透過在接觸程式碼之前從 README 檔案執行一些 docker run 命令來提供的,或者您可以使用類似 Docker Compose 的工具(Spring Boot 3.1 為此也添加了一些很酷的新功能)。

透過開發時的 Testcontainers,您現在擁有了另一個工具。為什麼只在整合測試中使用 Testcontainers?從技術上講,沒有什麼可以阻止您在生產程式碼中啟動 Testcontainers,然後設定屬性來連線到這些容器。即使在使用 Spring Boot 3.1 之前的版本,現在也可以這樣工作。

這種方法的缺點是,您現在需要在編譯類路徑上包含 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 會確保在應用程式停止時關閉容器。如果您更喜歡從終端執行應用程式,我們也能滿足您的需求。Spring Boot 的 Gradle 和 Maven 外掛已經學會執行此測試 main 方法。使用 Gradle,命令是 ./gradlew bootTestRun,使用 Maven,命令是 ./mvnw spring-boot:test-run

需要注意的一點是,每次重新啟動應用程式時,容器都會關閉,並且它們會丟失資料。這可以透過兩種方式解決:第一種是使用 Spring Boot devtools,然後為您的容器的 bean 方法加上 @RestartScope 註解。這些容器在 devtools 重新啟動應用程式時**不會**重新啟動。這意味著您不必每次更改應用程式中的某些內容時都等待容器啟動,並且容器會保留其資料。

第二種方式是 Testcontainers 中的一個名為可重用容器的功能。

@TestConfiguration(proxyBeanMethods = false)
public class MyContainersConfiguration {

    @Bean
    @ServiceConnection
    public Neo4jContainer<?> neo4jContainer() {
        return new Neo4jContainer<>("neo4j:5").withReuse(true);
    }

}

這些容器在應用程式關閉時不會停止。這是一個 Testcontainers 的**實驗性**功能,因此請自行承擔風險使用。

為了完整起見,這是我們目前支援的容器列表。

  • CassandraContainer
  • CouchbaseContainer
  • ElasticsearchContainer
  • 使用 redisopenzipkin/zipkinGenericContainer
  • JdbcDatabaseContainer
  • KafkaContainer
  • MongoDBContainer
  • MariaDBContainer
  • MSSQLServerContainer
  • MySQLContainer
  • Neo4jContainer
  • OracleContainer
  • PostgreSQLContainer
  • RabbitMQContainer
  • RedpandaContainer

我們希望您喜歡這些新功能,並希望它們能幫助您編寫更出色的應用程式。請閱讀文件以開始使用,如果您遇到任何問題或有改進此功能的想法,請與我們聯絡

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有