sano11o1

GoのテストはDockerコンテナ内部で実行するべきか?

公開日:

最近では開発環境をDockerを使って構築することが多いと思います。
さらに開発環境だけではなく結合テストに使用するサーバーにもDockerを利用できます。

dockertesttestcontainersといったパッケージを使うと、コンテナの起動、破棄をGoのテストコードの中に書くことができます。
以下は、testcontainersのサンプルコードです。

package main_test

import (
  "context"
  "log"
  "testing"

  "github.com/testcontainers/testcontainers-go"
  "github.com/testcontainers/testcontainers-go/wait"
)


func TestWithRedis(t *testing.T) {
  ctx := context.Background()
  req := testcontainers.ContainerRequest{
    Image:        "redis:latest",
    ExposedPorts: []string{"6379/tcp"},
    WaitingFor:   wait.ForLog("Ready to accept connections"),
  }
  redisC, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
    ContainerRequest: req,
    Started:          true,
  })
  if err != nil {
    log.Fatalf("Could not start redis: %s", err)
  }
  defer func() {
    if err := redisC.Terminate(ctx); err != nil {
      log.Fatalf("Could not stop redis: %s", err)
    }
  }()
}



go testコマンドを実行するだけでコンテナが起動し任意のテストを実行することができます。
非常に便利ですね。

ここで疑問が生じます。
go testコマンドを実行する環境(以下、テスト実行環境と呼ぶ)は、開発者のローカル環境で良いのだろうか?それとも何らかの方法でローカル以外の場所に隔離するべきか?隔離するとしたらDockerコンテナ内部で実行するべきか?という疑問です。

結論から書くとテスト実行環境はローカル環境で問題ないと私は考えます。

Dockerを導入するメリットの1つに、環境間、開発者間の差分を吸収し、どんな環境でも同様のアプリケーションの挙動を担保することが挙げられます。

上記コードの場合、テスト実行環境に発生する差分はGoのバージョンに絞られるでしょう。

テスト実行環境に差分が発生しにくい場合や差分を吸収する仕組みが既に存在する場合は、差分の吸収を自前で実装する必要はないでしょう。

Go言語の特性を考えると差分を吸収する仕組みの実装は不要と考えられます。

Go言語は後方互換性が担保されているため気軽に言語のバージョンを挙げることができます。
さらに、何らかの理由で固定する場合でもコマンドで任意のバージョンをインストール、実行できるため環境間、開発者間でバージョンを合わせることができます。
(詳細はこちら https://zenn.dev/tenntenn/articles/676a32ab3d4aab )

仮にDocker環境にテスト実行環境を隔離する場合、テスト実行用のコンテナを起動し、そのコンテナ内部でdockertestやtestcontainersのパッケージを使ってコンテナを起動する構成が考えられます。
この構成は中間のコンテナの管理が必要になり煩雑になる可能性があります。