まとめ
dockertestを使うとGo
のコード内からテスト対象のDBをDocker
コンテナとして起動して接続することができる.
これを使ってDBを都度立ち上げて, 実際にレコード操作の検証をするテストを書いてみた.
環境
- macOS Big Sur 11.2.3
- go version go1.15.5 darwin/amd64
- dockertest v3.3.5
- Docker Desktop for Mac
- Version 3.3.0
- Docker Engine Version 20.10.5
やりかた
この前はDBをモックしたテストを試したけど,
やっぱり実際にテスト用のDBを立てて期待値が得られるか検証したいときもある.
テスト対象となるのは前回同様こんな感じの処理.
今回はGoからDockerをいじることができるdockertestを使ってテスト用DBを起動し,
それに接続してテストを行う.
まずはテーブル定義を記述したファイルをつくる.
ついでにMySQL
の設定ファイルを作っておく.
次に公式の例1を参考に, MySQL
2のコンテナを立ち上げる関数を書いてみる.
頑張ったのはcreateContainer()
でRunOptions
3を使ってコンテナ起動時に細かいオプションを指定したり必要な設定ファイルをマウントできるようにしたところ.
こうしておくことで大体のDBの設定をこのテストコードに封じ込めることができる.
closeContainer()
を呼び忘れるとテストが終わってもコンテナが残ってしまうので注意する(defer
で呼んでおくのが良さそう).
各機能のテストではそれぞれこの関数を呼び出してテスト用のDBを作成する.
前回同様Create()
についてテストを作るとこんな感じ.
一応テスト対象の関数以外のDB操作(挿入したレコードを取得するときなど)もRead()
などの自分で定義している関数ではなく都度SQLを実行するようにした.
最終的なテストコードはこんな感じ.
最後にテストを実行してみる.
# ディレクトリの状態
$ tree .
.
├── go.mod
├── go.sum
├── main.go
├── main_test.go
├── my.cnf
└── todo.sql
# テスト実行
$ go test -v ./...
=== RUN TestCreateWithDB
=== RUN TestCreateWithDB/レコードが正しく追加されることのテスト
[mysql] 2021/05/13 23:41:36 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:41:36 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:41:36 packets.go:37: unexpected EOF
--- PASS: TestCreateWithDB (27.14s)
--- PASS: TestCreateWithDB/レコードが正しく追加されることのテスト (27.14s)
=== RUN TestReadWithDB
=== RUN TestReadWithDB/レコードが正しく取得できることのテスト
[mysql] 2021/05/13 23:42:03 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:03 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:03 packets.go:37: unexpected EOF
--- PASS: TestReadWithDB (26.95s)
--- PASS: TestReadWithDB/レコードが正しく取得できることのテスト (26.95s)
=== RUN TestUpdateWithDB
=== RUN TestUpdateWithDB/レコードが正しく更新できることのテスト
[mysql] 2021/05/13 23:42:30 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:30 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:30 packets.go:37: unexpected EOF
--- PASS: TestUpdateWithDB (27.15s)
--- PASS: TestUpdateWithDB/レコードが正しく更新できることのテスト (27.15s)
=== RUN TestDeleteWithDB
=== RUN TestDeleteWithDB/レコードが正しく削除できることのテスト
[mysql] 2021/05/13 23:42:58 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:58 packets.go:37: unexpected EOF
[mysql] 2021/05/13 23:42:58 packets.go:37: unexpected EOF
--- PASS: TestDeleteWithDB (28.51s)
--- PASS: TestDeleteWithDB/レコードが正しく削除できることのテスト (28.51s)
PASS
ok github.com/uzimihsr/golang-db-test 110.730s
コンテナを立ち上げてから疎通できるまでにちょっと時間がかかるのでunexpected EOF
のエラーが何回か出てるけど, 内部でリトライをしてるので問題ないはず.
都度Docker
の操作をしてるせいでかなり時間がかかっているので, t.Parallel()
4とかを使って並列実行させたほうが良いかも.
おわり
dockertestを使ってテスト用のMySQL
コンテナをGo
のコードから立てて操作してみた.
別にDB
に限らず外部とのやりとりをする部分は対象をDocker
化できるなら何でも使えちゃいそう.
ただしテスト環境でGo
以外にDocker
が必要になったり,
コンテナの立ち上げにかなり時間がかかるなどクセも強いのでどこまでやるかはテスト要件と相談して使いたい.