🐁

【Go言語】Testcontainers で PostgreSQL を起動する3つの方法

に公開

はじめに

コンテナを利用したテストを快適に実行するために Testcontainers というライブラリがあります。

https://github.com/testcontainers/testcontainers-go

テスト実行前の環境構築が不要であったり、テスト実行のたびにコンテナをクリーンアップできたり、コンテナを並列起動することでテストデータの干渉などを考えなくてよくなります。

似たようなライブラリで ory/dockertest というライブラリがありますが、現在は Testcontainers がおすすめされています。

https://github.com/ory/dockertest

https://zenn.dev/shiguredo/articles/go-test-dockertest

追記: 2024-07-20

Testcontainers を使いましょう。

この Testcontainers を利用して PostgreSQL との統合テストを実装しようと思ったのですが、コンテナを起動する方法がいくつか選択肢があったのでそれぞれ実装して比較してみました。

PostgreSQL コンテナ起動時に求めること

以下のことができればよいなという想定です。

  • 任意のユーザーやパスワードの設定
  • マイグレーションの実施
  • ヘルスチェック

3つの起動方法

https://golang.testcontainers.org/

ドキュメントを眺めてみた感じ、3つの方法で PostgreSQL コンテナはセットアップできそうでした。( PostgreSQL に限らず他のコンテナも同じ方式でセットアップはできそうです。 )

  1. 汎用的なコンテナ起動
  2. PostgreSQL モジュールの起動
  3. Docker Compose による起動

1. 汎用的なコンテナ起動

1つ目はクイックスタートにも記載されている関数 testcontainers.GenericContainer() を利用する方法です。

https://golang.testcontainers.org/quickstart/

この関数を使えば任意のコンテナが起動できます。

https://github.com/otakakot/sample-go-postgres-testcontainers/blob/8b3dcba18fdad840011a25bc57a4d43ebad41a5b/test/internal/testx/testx.go#L15-L102

docker-entrypoint-initdb.d を指定してマイグレーションを実施させます。
ディレクトリを指定したかったのですが、うまく動かなかったのでファイルごとにコピーするようにしています。

2. PostgreSQL モジュールの起動

2つ目はモジュールごとに用意された関数 postgres.Run() を利用する方法です。

https://golang.testcontainers.org/modules/postgres/

実際は1つ目で紹介した関数をモジュールごとに使いやすくラップしたものになります。

https://github.com/otakakot/sample-go-postgres-testcontainers/blob/8b3dcba18fdad840011a25bc57a4d43ebad41a5b/test/internal/testx/testx.go#L104-L170

各種設定値が専用のオプションとして設定できるので1つ目の方法よりパラメータの扱いが PostgreSQL に沿った形式で設定できます。
DSN 情報も専用のメソッドが用意されているので安全に接続情報を取得できます。
こちらも docker-entrypoint-initdb.d を指定してマイグレーションを実施させますが、1つ目の方法同様にディレクトリの指定ができなかったのでファイルごとにコピーする手法をとっています。

3. Docker Compose による起動

3つ目は Docker Compose ファイルを利用する関数 compose.NewDockerComposeWith()を利用する方法です。

https://golang.testcontainers.org/features/docker_compose/

compose.yaml ファイルを利用してコンテナを起動します。

https://github.com/otakakot/sample-go-postgres-testcontainers/blob/8b3dcba18fdad840011a25bc57a4d43ebad41a5b/test/compose.yaml

実行時に決定したい値は ${} で記載しておきます。

https://github.com/otakakot/sample-go-postgres-testcontainers/blob/8b3dcba18fdad840011a25bc57a4d43ebad41a5b/test/internal/testx/testx.go#L172-L220

マイグレーションについては compose.yamldocker-entrypoint-initdb.d で記載したとおりディレクトリがマウントされ実行されます。

おわりに

個人的には compose.yaml を利用したセットアップが好みです。
利用するイメージを compose.yaml で管理できるので renovate と組み合わせればバージョン更新漏れなどが減らせそうです。
また、サービス指定ができるのでローカル環境構築用のファイルと併用も可能かと思います。

今回実装したコードは以下に置いておきます。

https://github.com/otakakot/sample-go-postgres-testcontainers

Discussion