Testcontainer JDBC 支援

banq發表於2024-07-10

在這篇短文中,我們將瞭解 Testcontainers JDBC 支援,並比較在測試中啟動Docker 容器的兩種不同方式。

最初,我們將以程式設計方式管理 Testcontainer 的生命週期。之後,我們將透過單一配置屬性簡化此設定,並利用框架的 JDBC 支援。

手動管理測試容器生命週期
Testcontainers是一個提供輕量級一次性 Docker 容器用於測試的框架。我們可以使用它對真實服務(如資料庫、訊息佇列或 Web 服務)執行測試,而無需模擬或外部依賴。

假設我們想要使用 Testcontainers 來驗證與 PostgreSQL 資料庫的互動。首先,我們將testcontainers依賴項新增到我們的pom.xml中:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>testcontainers</artifactId>
    <version>1.19.8</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>1.19.8</version>
    <scope>test</scope>
</dependency>

之後,我們必須管理容器的生命週期,按照幾個簡單的步驟:
  • 建立容器物件
  • 在所有測試之前啟動容器
  • 配置應用程式以連線容器
  • 測試結束時停止容器

我們可以使用 JUnit5 和 Spring Boot 註釋(例如@BeforeAll、@AfterAll和@DynamicPropertyRegistry )自己實現這些步驟:

@SpringBootTest
class FullTestcontainersLifecycleLiveTest {
    static PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16-alpine")
      .withDatabaseName("test-db");
    @BeforeAll
    static void beforeAll() {
        postgres.start();
    }
    @DynamicPropertySource
    static void setProperties(DynamicPropertyRegistry registry) {
        registry.add("spring.datasource.url", postgres::getJdbcUrl);
        registry.add("spring.datasource.username", postgres::getUsername);
        registry.add("spring.datasource.password", postgres::getPassword);
    }
    @AfterAll
    static void afterAll() {
        postgres.stop();
    }
    // tests
}

儘管此解決方案允許我們自定義特定的生命週期階段,但它需要複雜的設定。幸運的是,該框架提供了一種方便的解決方案,可以使用最少的配置啟動容器並透過 JDBC 與它們通訊。

使用 Testcontainers JDBC 驅動程式
當我們使用 JDBC 驅動程式時,Testcontainers 將自動啟動託管我們資料庫的 Docker 容器。為此,我們需要更新測試執行的 JDBC URL,並使用以下模式:“jdbc:tc:<docker-image-name>:<image-tag>:///<database-name>”。

讓我們使用此語法在測試中更新spring.datasource.url :

spring.datasource.url: jdbc:tc:postgresql:16-alpine:///test-db


不用說,這個屬性可以在專用的配置檔案中定義,也可以透過@SpringBootTest註釋在測試本身中定義:

@SpringBootTest(properties =
  "spring.datasource.url: jdbc:tc:postgresql:16-alpine:///test-db"
)
class CustomTestcontainersDriverLiveTest {
    @Autowired
    HobbitRepository theShire;
    @Test
    void whenCallingSave_thenEntityIsPersistedToDb() {
        theShire.save(new Hobbit("Frodo Baggins"));
        assertThat(theShire.findAll())
          .hasSize(1).first()
          .extracting(Hobbit::getName)
          .isEqualTo("Frodo Baggins");
    }
}

我們可以注意到,我們不再需要手動處理 PostgreSQL 容器的生命週期。測試容器處理了這種複雜性,使我們能夠專注於手頭的測試。

相關文章