Go言語でのテーブル駆動テストで失敗するテストケースを見つける方法
Go言語では、テーブル駆動テストが良い慣習としてよく知られています。
行動とデータを分割するのは素晴らしいのですが、現在のGoのテストでは、失敗したテストケースを見つけるのが直感的ではありません。代わりに、失敗したテスト表明の行番号が出るだけで、これは役に立ちません。
下の例を見てください:
package eg
import "testing"
func TestExample(t *testing.T) {
testcases := []struct {
name string
a, b int
sum int
}{
{"1+1", 1, 1, 99},
{"2+2", 2, 2, 4},
{"4+4", 4, 4, 8},
// [長いコード行...]
{"1024+1024", 1024, 1024, -1},
}
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
if got, expected := testcase.a+testcase.b, testcase.sum; got != expected {
t.Errorf("expected %d, got %d", expected, got)
}
})
}
}
テストを実行すると、次のような出力が得られます:
--- FAIL: TestExample (0.00s)
--- FAIL: TestExample/1+1 (0.00s)
eg_test.go:100: 期待値99, 結果2
--- FAIL: TestExample/1024+1024 (0.00s)
eg_test.go:100: 期待値-1, 結果2048 # <-- これは表明の行番号であって、テストケースのものではありません
どのテストケースが失敗したかに関わらず同じ行番号ばかりです。実際には、テストケース自体が失敗した行番号を見たいものです。テスト名では失敗したテストケースが何かある程度教えてくれるかもしれませんが、十分ではありません。
この問題を解決するために、私は小さなヘルパー・ライブラリを作成しました:go-testutil/dataloc。
https://pkg.go.dev/github.com/motemen/go-testutil/dataloc
[#使用方法]使用方法
上記の例を使用して、コードを少し変更してみましょう:
@@ -1,6 +1,7 @@
package eg
import "testing"
+import "github.com/motemen/go-testutil/dataloc"
func TestExample(t *testing.T) {
testcases := []struct {
@@ -96,7 +97,7 @@
for _, testcase := range testcases {
t.Run(testcase.name, func(t *testing.T) {
if got, expected := testcase.a+testcase.b, testcase.sum; got != expected {
- t.Errorf("expected %d, got %d", expected, got)
+ t.Errorf("期待値%d, 結果%d, テストケース位置 %s", expected, got, dataloc.L(testcase.name))
}
})
}
...それを実行すると、次のような出力が得られます。これは_アサーションの位置ではなく、失敗したテストケースの_場所を示しています。
--- FAIL: TestExample (0.00s)
--- FAIL: TestExample/1+1 (0.00s)
eg_test.go:100: 期待値99, 結果2, テストケース位置 eg_test.go:12
--- FAIL: TestExample/1024+1024 (0.00s)
eg_test.go:100: 期待値-1, 結果2048, テストケース位置 eg_test.go:95
[#内部の仕組み]内部の仕組み
この魔法を実現するために、ライブラリはruntime.Callerを使用して呼び出し元のファイルと行番号を取得し、次にgo/astを使用してファイルを解析し、対応するテストケースの位置を見つけます。
dataloc.L(testcase.name)
の形をした呼び出しを見つけるtestcase
の起源であるfor ... range testcases
を見つけるtestcases
の定義を見つける- 実行時の値
testcase.name
("1+1" など)のテストケースの名前を持つテストケースの定義を見つける。- テストケース名が静的に決定されていない場合は、特定できません。
楽しいテーブル駆動テストを!
こちらの記事はdev.toの良い記事を日本人向けに翻訳しています。
https://dev.to/motemen/locating-failing-test-cases-in-table-driven-tests-in-go-77m