Skip to content

testcontainers を使ってテスト実行

テスト実行時のみデータベースコンテナを作成してテストを行うためのサンプルコードです。

repository についてはテスト向けのデータベースが必要となります。

パッケージインストール

go get github.com/testcontainers/testcontainers-go/modules/mariadb
go get github.com/docker/docker/client

テストデータベース作成

下記関数でテスト向けデータベースのコンテナを構築します。

// テスト用データベースに接続します。
func connectTestDB(t *testing.T) *sql.DB {

    // コンテナ環境が無ければテストスキップ
    cli, err := client.NewClientWithOpts(client.FromEnv)
    if err != nil {
        t.Fatal(err)
    }
    _, err = cli.Ping(context.Background())
    if err != nil {
        t.Skip("コンテナ環境が無いためテストをスキップします。")
    }

    const image string = "mariadb:latest"
    const testdata string = "testdata"
    const testrepo string = "userinfo"
    const sqlFile string = "create-table.sql"
    const user string = "root"
    const password string = ""
    const host string = "localhost"
    const dbName string = "snaildb"
    const driverName string = "mysql"

    // MariaDBコンテナ起動
    ctx := context.Background()
    mariadbContainer, err := mariadb.Run(ctx,
        image,
        mariadb.WithScripts(filepath.Join(testdata, testrepo, sqlFile)), // 初期スクリプトのパス
        mariadb.WithUsername(user),
        mariadb.WithPassword(password),
        mariadb.WithDatabase(dbName),
    )
    if err != nil {
        t.Fatal(err)
    }

    // ポートをマッピング
    port, err := mariadbContainer.MappedPort(ctx, "3306")
    if err != nil {
        t.Fatal(err)
    }

    // データベースに接続
    dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s", user, password, host+":"+port.Port(), dbName)
    db, err := sql.Open(driverName, dsn)
    if err != nil {
        t.Fatal(err)
    }

    // 実際に接続できるかを確認
    err = db.Ping()
    if err != nil {
        t.Fatal(err)
    }

    return db
}

各テストケースにて上記関数を呼び出してからテストを実行してください:

// userInfoRepository_Insertのテスト
func Test_userInfoRepository_Insert(t *testing.T) {

    tests := []struct {
        // 省略
    }

    for _, testcase := range tests {

        t.Run(testcase.name, func(t *testing.T) {

            // テストデータベースおよびrepository初期化
            db := connectTestDB(t)
            r := &userInfoRepository{db: db}

            // repositoryの実行
            err := r.Insert(testcase.requestEntity)

            // レスポンスの確認
            assert.Equal(t, testcase.expectedError, err)
        })
    }
}