メインコンテンツへスキップ
SDETRole
SDETRole

用語集 · CI/CD と DevOps

Testcontainers

別名: Testcontainers for Java, testcontainers-node, テストコンテナ, テストコンテナーズ

定義

データベース、メッセージブローカー、ブラウザーなどの本物の依存関係を、テストコードから使い捨ての Docker コンテナとして起動し、終了後に削除するライブラリです。

Testcontainers は、Java、Node.js、.NET、Go、Python などの言語で使えるオープンソースのライブラリで、テストの中から Docker を操作します。テストが「Postgres 16 のデータベース」を要求すると、ライブラリがコンテナを起動し、準備ができるまで待ち、接続情報を渡し、テストが終わるとコンテナを削除します。インメモリの代用品や共有環境ではなく、本物のデータベースエンジンに対してテストできます。

例(Testcontainers for Java 1.x、JUnit 5)

import org.junit.jupiter.api.Test;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;

import static org.junit.jupiter.api.Assertions.assertTrue;

@Testcontainers
class DatabaseIT {

    @Container
    static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres:16-alpine");

    @Test
    void canQueryTheDatabase() throws Exception {
        try (Connection conn = DriverManager.getConnection(
                postgres.getJdbcUrl(), postgres.getUsername(), postgres.getPassword());
             ResultSet rs = conn.createStatement().executeQuery("SELECT 1")) {
            assertTrue(rs.next());
        }
    }
}

static フィールドにすると、クラス内のすべてのテストで 1 つのコンテナを共有します。インスタンスフィールドにすると、テストごとに新しいコンテナが起動します。実際のスイートでは、リポジトリや Spring のコンテキストを getJdbcUrl() に向け、先にマイグレーションを実行します。

なぜ重要なのか

H2 や SQLite に対する結合テストは合格しても、本番のデータベースでは同じ SQL が拒否されることがよくあります。方言、制約、トランザクションの挙動が異なるからです。Testcontainers を使えば、モックに近い手軽さで本物のエンジンを使えます。さらに毎回クリーンな状態から始まるため、共有データに起因するフレーキーさもなくなります。

知っておくべきこと

  • マシン上と CI ランナー上に Docker 互換のランタイムが必要です。GitHub がホストする Ubuntu ランナーでは Docker を利用できます。
  • コンテナの起動には数秒かかります。コンテナはクラス単位またはスイート単位で共有し、テスト間ではコンテナを再起動するのではなくデータをリセットしましょう。
  • イメージのバージョンは本番に合わせて固定しましょう。
  • よく使われるサービス(Postgres、MySQL、Kafka、LocalStack、Selenium など)にはすぐに使えるモジュールがあり、それ以外のイメージは GenericContainer で扱えます。
  • テストダブルを置き換えるものではなく、補完するものです。ユニットテストは引き続きインメモリで高速に保つべきです。

キーワードを入力すると SDETRole 全体を検索できます。

Pagefind による全文検索 · ブラウザ内で動作します 検索ページを開く →