Testcontainersとは
Testcontainers
は、データベース、メッセージ・ブローカー、ウェブ・ブラウザなど、Docker
コンテナで動作するあらゆるものの軽量インスタンスを提供するためのオープンソース・ライブラリです。
テストの依存関係をコードとして定義し、テストを実行するだけで、コンテナが作成され、削除されます。
モックや複雑な環境設定はもう必要ありません。
多くの言語とテストフレームワークをサポートしており、必要なのはDocker
だけです。
背景
2023年12月、Docker社がTestcontainers
の開発元であるAtomicJar社を買収したことが発表されました。
これにより、Testcontainers
の開発はさらに活発になることが予想されます。
今まで、GoのDBのテストにはdockertest
を使っていましたが、この機会にTestcontainers
を使ってみることにしました。
サンプルコード
以下のコードは、Testcontainers for Goで、PostgreSQLのデータベースを使用してテストを行うサンプルです。
package test
import (
"context"
"database/sql"
"log"
"path/filepath"
"testing"
"time"
"github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/modules/postgres"
"github.com/testcontainers/testcontainers-go/wait"
_ "github.com/lib/pq"
)
var db *sql.DB // データベース接続用のグローバル変数
// テスト全体のセットアップとクリーンアップを管理するエントリポイント
func TestMain(m *testing.M) {
ctx := context.Background()
// データベースの設定情報
dbName := "users"
dbUser := "user"
dbPassword := "password"
// PostgreSQLコンテナを起動
postgresContainer, err := postgres.Run(ctx,
"postgres:16-alpine", // 使用するPostgreSQLイメージ
postgres.WithInitScripts(filepath.Join("testdata", "init.sql")), // 初期化スクリプトを指定
postgres.WithDatabase(dbName), // データベース名を指定
postgres.WithUsername(dbUser), // ユーザー名を指定
postgres.WithPassword(dbPassword), // パスワードを指定
testcontainers.WithWaitStrategy( // コンテナの起動完了を待つための戦略
wait.ForLog("database system is ready to accept connections"). // 特定のログ出力を待機
WithOccurrence(2). // ログが2回出現するまで待つ
WithStartupTimeout(5*time.Second)), // タイムアウトを設定
)
defer func() {
// テスト終了後にコンテナを停止
if err := testcontainers.TerminateContainer(postgresContainer); err != nil {
log.Fatalf("failed to terminate container: %s", err)
}
}()
if err != nil {
log.Fatalf("failed to start container: %s", err)
}
// PostgreSQLへの接続文字列を取得
dbURL, err := postgresContainer.ConnectionString(ctx, "sslmode=disable")
if err != nil {
log.Fatalf("error: %s", err)
}
// データベース接続を初期化
db, err = sql.Open("postgres", dbURL)
if err != nil {
log.Fatalf("error: %s", err)
}
defer db.Close() // テスト終了時に接続を閉じる
// テストを実行
m.Run()
}
// 実際のテストケース(例)
func TestXXX(t *testing.T) {
// ここにテストケースを記述
}
感想
dockertest
には、Testcontainers
のようなpostgres.WithInitScripts
に相当する初期化スクリプトを実行する仕組みがないので、Testcontainers
は便利だなと思いました。