Closed16

Testcontainers for Go を使ってみる

u1u1

手元のDocker環境はcolimaを利用しています。

docker version
Client: Docker Engine - Community
 Version:           23.0.1
 API version:       1.41 (downgraded from 1.42)
 Go version:        go1.19.5
 Git commit:        a5ee5b1dfc
 Built:             Thu Feb  9 19:15:59 2023
 OS/Arch:           darwin/arm64
 Context:           default

Server:
 Engine:
  Version:          20.10.11
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.4
  Git commit:       847da184ad5048b27f5bdf9d53d070f731b43180
  Built:            Wed Apr 13 23:41:08 2022
  OS/Arch:          linux/arm64
  Experimental:     false
 containerd:
  Version:          v1.5.8
  GitCommit:        1e5ef943eb76627a6d3b6de8cd1ef6537f393a71
 runc:
  Version:          1.0.0-rc95
  GitCommit:        b9ee9c6314599f1b4a7f497e1f1f856fe433d3b7
 docker-init:
  Version:          0.19.0
  GitCommit:        
u1u1

.zshrc に以下を書いたら良さそうか。

# testcontainers
export DOCKER_HOST="unix://${HOME}/.colima/default/docker.sock"
export TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE="/var/run/docker.sock"
u1u1

TESTCONTAINERS_RYUK_DISABLED はあってもなくても動いた。
ひとまず細かい動作の違いは見ていない。

u1u1

VSCodeのUI上からテストコードを実行しようとすると環境変数が適用されてなさそうなのはどうすれば良いか?

u1u1

.vscode/launch.json に記載するというのもあるが二重管理だしなんかそれじゃない感がある。

        {
            "name": "Launch Program",
            "type": "go",
            "request": "launch",
            "mode": "test",
            "program": "${fileDirname}",
            "env": {
                "DOCKER_HOST": "unix:///Users/xxxxx/.colima/default/docker.sock",
                "TESTCONTAINERS_DOCKER_SOCKET_OVERRIDE": "/var/run/docker.sock",
                "TESTCONTAINERS_RYUK_DISABLED": "true",
            },
            "args": [
                "-test.v",
                "-test.run",
                "TestYourFunc"
            ],
        }

u1u1

VSCode自体を一度終了させて起動したら反映されたぽいがそれしか方法ないのかな?

u1u1

初期データは test/dbdata にsqlファイル置いて /docker-entrypoint-initdb.d としてマウントさせれば取り込まれてそう。

func NewTestDatabase(t *testing.T) *TestDatabase {
	initdbDir, _ := filepath.Abs("../../test/dbdata")

	ctx, cancel := context.WithTimeout(context.Background(), time.Minute*5)
	defer cancel()
	req := testcontainers.ContainerRequest{
		Image:        "postgres:14",
		ExposedPorts: []string{"5432/tcp"},
		AutoRemove:   true,
		Env: map[string]string{
			"POSTGRES_USER":     "user",
			"POSTGRES_PASSWORD": "password",
			"POSTGRES_DB":       "testdb",
		},
		Mounts: testcontainers.ContainerMounts{
			testcontainers.BindMount(initdbDir, "/docker-entrypoint-initdb.d"),
		},
		WaitingFor: wait.ForListeningPort("5432/tcp").WithStartupTimeout(time.Minute * 2),
	}
	postgres, err := testcontainers.GenericContainer(
		ctx,
		testcontainers.GenericContainerRequest{
			ContainerRequest: req,
			Started:          true,
		},
	)
	require.NoError(t, err)
	return &TestDatabase{
		instance: postgres,
	}
}

u1u1

/docker-entrypoint-initdb.d に置いたファイルはファイル名でソートして昇順に実行されるらしい。
prefixに 0001_ , 0002_ などとつけておけば複数ファイルを置いても意図した順番で実行できそう。

u1u1

サポートされているファイルは .sh, .sql , .sql.gz

u1u1

テストが途中でコケたり通ったりする場合はタイムアウトしていることがあるので確認してタイムアウト値を伸ばしましょう

現状はこんな感じのオプションでテスト実行している

go test -timeout 180s -short -race ./...
u1u1

個人的な結論としてはTestcontainers for Goは結構良さそうで、全パターン網羅するようなテストを書くかは置いておいて、クエリ書く時に関数単位ですぐに動かして試せる環境を持てるのが良いと思う。

このスクラップは2023/05/09にクローズされました