docker/compose は Go で書かれてるが、これのテストに gotest.tools というライブラリが使われていた。あまり見たことがなかったけど、使ってみたらわりと手触りがよかったのでここに記しておく。
gotest.tools はいつもの testing パッケージを拡張するようなライブラリ集。あとテストを実行するための CLI も提供している。GitHub Org は gotestyourself という名前だけど、これは洒落てるのかどうか不明(洒落てないほうに賭ける)。
assert, cmp
gotest.tools/v3/assert が多分このライブラリのコア。主な API は assert.Check(t, comparison, msgAndArgs...)
で、シグネチャを見たらあーそういうやつねと分かると思う。
予想通り comparison
の中身しだいで t.Fail()
するかどうか決めてくれるものだが、ここに単に false (bool) を渡したときが便利で、ただ「true じゃなかったよ」と言うのではなくどんな式を評価した結果そうなったのかを教えてくれる。
package main import ( "testing" "gotest.tools/v3/assert" ) func add(x, y int) int { return x - y // BUG } func TestAdd(t *testing.T) { // assertion failed: expression is false: add(1, 2) == 3 assert.Check(t, add(1, 2) == 3) }
add(1, 2) == 3
が偽だったと。なるほど。テストにいちいちメッセージを書いていくのは面倒なので、真偽を返す式からメッセージを組み立ててくれるのはありがたい。
この comparison
には error(もちろん nil のときにテストが通る) を渡せるほかに、cmp.Comparison
を与えることもできる。よくあるメッセージつきのカスタム比較構造体だけど、このファミリーにある cmp.DeepEqual()
では内部で google/go-cmp を利用している。
基本的に Go のテストは素の testing で書き、複雑になってきたら go-cmp を使う、という感じに書いてたのでこれは便利だった。
package main import ( "testing" "gotest.tools/v3/assert" // is という名前でインポートしてほしいらしい is "gotest.tools/v3/assert/cmp" ) type Record struct { X int } func TestRecord(t *testing.T) { expected := Record{ X: 1, } got := Record{ X: 666, } // assertion failed: // --- expected // +++ got // main.Record{ // - X: 1, // + X: 666, // } assert.Check(t, is.DeepEqual(expected, got)) }
ここでも地味に、メッセージ中に渡した変数名が使われていてありがたいですね。
gotestsum
ライブラリじゃないけど gotestsum というツールも提供している。これは go test
の代替みたいな趣。README にあるスクリーンキャストを見ると様子がわかる。ドットが並んでるやつがかっこいい。
……のだけど docker/compose の v2 ブランチではしれっと使わなくなってたのでもうディスコンなのかもしれない。
ほかにもいくつかパッケージはある
けど、あと面白いのは skip くらいかな。assert と cmp くらいにとどめておくのが、つかず離れずでいいんじゃないだろうか。