testcontainer-goを試す
はじめに
JavaのライブラリーにTestcontainersと呼ばれるものがありますが、そいつのGo版ライブラリがあると言うのを見かけたので試してみたい思います。
Testcontainersとは
TestcontainersはJavaのライブラリーでDocker ContainerをJunitのライフサイクルに合わせてコンテナの作成、削除等の操作できたり、SeleniumやPostgres DBなどのインテグレーションテストで利用するようなコンテナの利用をサポートしていたりします。
TestContainers-Goとは
Testcontainer-GoはTestContainersのGoの実装でです。 Docker Engine SDKをベースに作られています。
このブログを書いている現在はVersionがv0.5.1
で本家ほどのテストライブラリに対するサポートなどは無いようです。
使ってみる
環境
$ uname -srvmpio Linux 5.3.0-59-generic #53~18.04.1-Ubuntu SMP Thu Jun 4 14:58:26 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux $ lsb_release -a LSB Version: core-9.20170808ubuntu1-noarch:security-9.20170808ubuntu1-noarch Distributor ID: Ubuntu Description: Ubuntu 18.04.4 LTS Release: 18.04 Codename: bionic $ go version go version go1.14.4 linux/amd64 $ docker -v Docker version 19.03.11, build 42e35e61f3
Testcontainers-Goのインストール
まずは、モジュールプロジェクトを作成して、Testcontainers-Goをインストールします。
$ go mod init hello-testcontainers $ go get github.com/testcontainers/testcontainers-go
コンテナを作成してみる
Testcontainers-Goを使ってNginxのコンテナを作成して、リクエストを送ってみます。
package hello_testcontainers__test import ( "context" "fmt" "github.com/testcontainers/testcontainers-go" "github.com/testcontainers/testcontainers-go/wait" "io/ioutil" "net/http" "testing" ) func TestHelloTestContainer(t *testing.T) { cxt := context.Background() request := testcontainers.ContainerRequest{ Image: "nginx", ExposedPorts: []string{"80/tcp"}, WaitingFor: wait.ForHTTP("/"), } container, err := testcontainers.GenericContainer(cxt, testcontainers.GenericContainerRequest{ ContainerRequest: request, Started: true, }) checkErr(t, err) defer container.Terminate(cxt) host, err := container.Host(cxt) checkErr(t, err) port, err := container.MappedPort(cxt, "80") checkErr(t, err) resp, err := http.Get(fmt.Sprintf("http://%s:%s", host, port.Port())) checkErr(t, err) body, err := ioutil.ReadAll(resp.Body) checkErr(t, err) if resp.StatusCode != http.StatusOK { t.Errorf("get wrong status code") } fmt.Println(string(body)) } func checkErr(t *testing.T,err error) { if err != nil { t.Error(err) } }
testcontainers.ContainerRequest
はコンテナ実行に必要なパラメータを持つための構造体です。上記のコードでは、作成するイメージの名前と、Exposeするポート、そして、NginxコンテナのReadinessをチェックするためのストラテジーを設定しています。
testcontainers.ContainerRequest
を使用してGenericContainerを作成しています。
container, err := testcontainers.GenericContainer(cxt, testcontainers.GenericContainerRequest{
ContainerRequest: request,
Started: true,
})
checkErr(t, err)
このコートが実行される際に実際にコンテナが作成します。 試しにこのコードが実行された後でコードの実行をポーズしてみて実行中のイメージを見てみると、Nginxのコンテナが作成され実行されているのがわかります。
$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 5531bb0974ad nginx "/docker-entrypoint.…" 8 seconds ago Up 8 seconds 0.0.0.0:32785->80/tcp vigorous_dubinsky e94eebca8f70 quay.io/testcontainers/ryuk:0.2.3 "/app" 9 seconds ago Up 8 seconds 0.0.0.0:32784->8080/tcp ecstatic_wilbur
nginxとは別にquay.io/testcontainers/ryuk:0.2.3
のコンテナも作成されています。このコンテナはmoby-ryukuと呼ばれる。
Testcontainersが用意しているコンテナの削除を補助するためのコンテナです。
container.Terminate(cxt)
はコンテナを停止するための関数でdefer
で実行することによって、コードの実行が終わった後に呼び出してコンテナを停止しています。
host, err := container.Host(cxt)
checkErr(t, err)
port, err := container.MappedPort(cxt, "80")
checkErr(t, err)
上記の箇所では、起動されるコンテナのホストと、コンテナ内の80に対してポートフォワードされるポートを取得することができます。
コードの最後の部分では、
host
とport
を使ってコンテナ内のnginxに対してHttpのゲットリクエストを送り、HTTPステータスをアサーションし、レスポンスボディを出力しています。
上記のコードを実行すると、テストが成功し、以下の出力を得ることができます。
GOROOT=/usr/local/go #gosetup GOPATH=/home/yuya-hirooka/go #gosetup /usr/local/go/bin/go test -c -o /tmp/___TestHelloTestContainer_in_hello_testcontainers -gcflags "all=-N -l" hello-testcontainers #gosetup /usr/local/go/bin/go tool test2json -t /home/yuya-hirooka/.local/share/JetBrains/IntelliJIdea2020.1/intellij-go/lib/dlv/linux/dlv --listen=localhost:34941 --headless=true --api-version=2 --check-go-version=false --only-same-user=false exec /tmp/___TestHelloTestContainer_in_hello_testcontainers -- -test.v -test.run ^TestHelloTestContainer$ #gosetup API server listening at: 127.0.0.1:34941 === RUN TestHelloTestContainer 2020/06/13 14:55:04 Starting container id: e94eebca8f70 image: quay.io/testcontainers/ryuk:0.2.3 2020/06/13 14:55:04 Waiting for container id e94eebca8f70 image: quay.io/testcontainers/ryuk:0.2.3 2020/06/13 14:55:05 Container is ready id: e94eebca8f70 image: quay.io/testcontainers/ryuk:0.2.3 2020/06/13 14:55:05 Starting container id: 5531bb0974ad image: nginx 2020/06/13 14:55:05 Waiting for container id 5531bb0974ad image: nginx 2020/06/13 14:55:05 Container is ready id: 5531bb0974ad image: nginx <!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to nginx!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html> --- PASS: TestHelloTestContainer (144.01s) PASS Debugger finished with exit code 0
また、テスト実行後はコンテナは削除されています。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
感想
使ってみましたが、本家ほどのテストライブラリーなどに対するサポートは無いようです。 一旦コンテナの起動、実行、削除に関する一通りのことができるくらいのものが用意されている理解です。