こんにちは。KOUKIです。
Go言語を使って、Webアプリケーション開発をしています。
今日は、Table Driven Testsを簡単に実装できるgotestsをご紹介しようと思います。
<目次>
WorkSpace
ワークスペースを作成してください。
1 2 3 4 5 |
mkdir go-test-sample cd go-test-sample/ touch culc.go touch culc_test.go go mod init test-sample |
Table Driven Testsって何?
Table Driven Testsは、テストコードの重複をできるだけ少なくするテスト手法の一つです。
例えば、以下のコードがあるとします。
1 2 3 4 5 6 |
// culc.go package culc func plus(a, b int) int { return a + b } |
この関数に対してテストコードを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
// culc_test.go package culc import ( "testing" "github.com/magiconair/properties/assert" ) func TestPlusOK(t *testing.T) { expected := 30 a := 10 b := 20 result := plus(a, b) assert.Equal(t, expected, result) } |
このテストは実行後、以下の結果を得られます。
1 2 3 4 |
$ go test testing: warning: no tests to run PASS ok test-sample 0.869s |
このままでも問題ありませんが、検査したい値が増えたときは、テストケースが増え、コードの重複が目立つようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// culc_test.go package culc import ( "testing" "github.com/magiconair/properties/assert" ) func TestPlusOK(t *testing.T) { expected := 30 a := 10 b := 20 result := plus(a, b) assert.Equal(t, expected, result) } func TestPlusOK2(t *testing.T) { expected := 40 a := 20 b := 20 result := plus(a, b) assert.Equal(t, expected, result) } func TestPlusOK3(t *testing.T) { expected := 0 a := 10 b := -10 result := plus(a, b) assert.Equal(t, expected, result) } |
この問題を解決するテスト手法の一つが、Table Driven Testsというわけです。
こんな感じで実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
// culc_test.go package culc import ( "testing" "github.com/magiconair/properties/assert" ) // テストケース構造体を定義 type TestCase struct { title string expect int a int b int } func TestPlusOK(t *testing.T) { testCases := []TestCase{ {"Test1", 30, 10, 20}, {"Test2", 40, 20, 20}, {"Test3", 0, 10, -10}, } for _, tc := range testCases { t.Run(tc.title, func(t *testing.T) { result := plus(tc.a, tc.b) assert.Equal(t, tc.expect, result) }) } } |
TestCaseという構造体を用意して、テストデータをスライスで保存しました。
これでだいぶコードがスッキリしましたね^^
1 2 3 4 5 6 7 8 9 10 11 |
$ go test -v === RUN TestPlusOK === RUN TestPlusOK/Test1 === RUN TestPlusOK/Test2 === RUN TestPlusOK/Test3 --- PASS: TestPlusOK (0.00s) --- PASS: TestPlusOK/Test1 (0.00s) --- PASS: TestPlusOK/Test2 (0.00s) --- PASS: TestPlusOK/Test3 (0.00s) PASS ok test-sample 0.785s |
gotestsを使ってみよう!
Table Driven Testsは大変便利でそれだけでも強力な武器になりますが、gotestsと組み合わせるともっと実装が楽になります。
まずは、gotestsを以下のコマンドでインストールしましょう。
1 2 3 4 5 6 7 8 9 10 11 |
// gotestsインストール go get -u github.com/cweill/gotests/... # ヘルプを確認 $ gotests -help Usage of gotests: -all generate tests for all functions and methods ... -w write output to (test) files instead of stdout |
次に、以下のコマンドでテストコードを自動出力します。
1 2 |
$ gotests -all -w culc.go Generated Test_plus |
cucl_test.goを確認してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
// culc_test.go package culc import ( "testing" "github.com/magiconair/properties/assert" ) // 自分で実装したコード // テストケース構造体を定義 type TestCase struct { title string expect int a int b int } func TestPlusOK(t *testing.T) { testCases := []TestCase{ {"Test1", 30, 10, 20}, {"Test2", 40, 20, 20}, {"Test3", 0, 10, -10}, } for _, tc := range testCases { t.Run(tc.title, func(t *testing.T) { result := plus(tc.a, tc.b) assert.Equal(t, tc.expect, result) }) } } // ここから自動生成したコード func Test_plus(t *testing.T) { type args struct { a int b int } tests := []struct { name string args args want int }{ // TODO: Add test cases. } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { if got := plus(tt.args.a, tt.args.b); got != tt.want { t.Errorf("plus() = %v, want %v", got, tt.want) } }) } } |
Test_plus関数が、自動生成したコードです。めちゃくちゃ簡単に、テストコードが実装できましたね^^
おわりに
gotestsには他にもオプションがあるので、色々試してみようと思います。
しかし、「gotests -all -w culc.go」を知っておけば、もう本当に便利ですね^^
ガンガン活用していきましょう!
それでは、また!
コメントを残す
コメントを投稿するにはログインしてください。