[Go] テストを実行する(go testの利用)
こんにちは、@yoheiMuneです。
最近Go言語によく触れていますが、新しい言語でもやっぱりテストは書きたい。テストを書くと自信を持ってリファクタリングできたり追加要件を開発できたりするので、僕の中ではプログラミングでの強い支えになっています。そんなテストをGo言語で書く方法をブログに書きたいと思います。
ここでは、以下の実装ファイルに対してテストを作成していきます。
ここでは
また、実装ファイルとテストファイルは同一パッケージ内に配置します。
ここではmainパッケージに、どちらのファイルも配置します。
例えば、echoというライブラリだと、以下のような感じで実装ファイルとテストファイルが並んで配置されています。
なお上記のように、入力値と期待値の一覧を作成して、for文でテストしていくのが、Goらしいテストの書き方のようです(個人的には少し慣れないですが、Do as Roman do の思想でまずはやってみようかなと思ってます)。
逆にテスト失敗があると、以下のような表示になります。
さらに
テスト失敗した場合には、以下のような表示になります。
Goのテストの基本と開発フロー // Speaker Deck
go標準のbenchmark機能の使い方 - Qiita
最後になりますが本ブログでは、Go言語・Python・Linux・フロントエンド・Node.js・インフラ・開発環境・Swift・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!
最近Go言語によく触れていますが、新しい言語でもやっぱりテストは書きたい。テストを書くと自信を持ってリファクタリングできたり追加要件を開発できたりするので、僕の中ではプログラミングでの強い支えになっています。そんなテストをGo言語で書く方法をブログに書きたいと思います。
目次
Goでテスト
Go言語では、テストを行う仕組みが提供されていて、それを使うことで簡単にテストができます。ここでは、以下の実装ファイルに対してテストを作成していきます。
package main import ( "math" ) // 値を2乗する func Square(x int) int { result := math.Pow(float64(x), 2.0) return int(result) }
テストファイルを作成する
Go言語では、テストファイルの命名規則があります。「対象ファイル名_test.go」でテストファイルを作成します。ここでは
calculator.go
をテストするので、calculator_test.go
となります。また、実装ファイルとテストファイルは同一パッケージ内に配置します。
ここではmainパッケージに、どちらのファイルも配置します。
例えば、echoというライブラリだと、以下のような感じで実装ファイルとテストファイルが並んで配置されています。
テストコードを実装する
テストコード実装では、testing
パッケージを利用します。calculator.go
のSquare
関数に対するテストは、以下のように実装します。package main // testingというパッケージを利用 import ( "testing" ) // 入力値(in)と期待値(out)を定義する構造体を作成(mapなどで代替しても良い) type squareTest struct { in, out int } // テストをしたい入力値と期待値の一覧を作成 var squareTests = []squareTest { squareTest{1, 1}, squareTest{2, 4}, squareTest{5, 25}, squareTest{-2, 4}, } // テスト関数を作成する // 関数名は「Test」をプレフィックスにつけ、引数には「t *testing.T」を渡す. func TestSqure( t *testing.T) { // 入力値と期待値を1件ずつテストする. for _, st := range squareTests { v := Square(st.in) if v != st.out { // テストNGがあればエラーにする(エラー内容がわかるようにメッセージをちゃんと書く) t.Errorf("Square(%d) = %d, want %d.", st.in, v, st.out) } } }テスト用の関数は
TestXXX
と、Testを関数名のプレフィクスに付与し、引数をt *testing.T
とします。なお上記のように、入力値と期待値の一覧を作成して、for文でテストしていくのが、Goらしいテストの書き方のようです(個人的には少し慣れないですが、Do as Roman do の思想でまずはやってみようかなと思ってます)。
テストを実行する
テストの実行は、go test
にて行います。$ go test # PASS # ok github.com/yoheiMune/MyGoProject/testtest 0.007sすべてのテストが通過すれば、上記のようにテストOKト表示されます。
逆にテスト失敗があると、以下のような表示になります。
# テスト失敗の例(入力値=-2, 期待値=-4と間違えた場合) $ go test --- FAIL: TestSqure (0.00s) main_test.go:22: Square(-2) = -4, want 4. FAIL exit status 1 FAIL github.com/yoheiMune/MyGoProject/testtest 0.008sと、エラーが表示されます。ここでエラーが分かるように(他の人にも分かるように)、ちゃんとエラーメッセージを書いておくと、メンテナンスしやすいコードになります。
テスト対象を絞る
テスト対象を指定して実行することもできます。# 指定パッケージのみテスト $ go test github.com/yoheiMune/MyGoProject/testtest # カレントディレクトリのみテスト $ go test -run "" # 指定ディレクトリ以下を再帰的にテスト go test -v hoge/... # 関数名を指定してテスト $ go test -run Squareと、いろいろな指定で絞り込んでテストが可能です。特定の機能を実装している時とかに便利ですね。
ベンチマークテスト
テスト対象のパフォーマンス計測も、言語ネイティブの機能でテストをすることができます。他の言語には無い特徴で、すごく良いと思います。ベンチマーク用のテストを追加
関数名はBenchmarkXXXX
とし、引数をb *testing.B
にすることでベンチマークテストを実装できます。// ベンチマーク. func BenchmarkSquare(b *testing.B) { for i := 0; i < b.N; i++ { Square(10) } }
b.N
回処理を実行して、パフォーマンスを計測します。ベンチマークテストを実行する
実行するには-bench
オプションを付与します。# ベンチマークテストを実行 $ go test -bench . BenchmarkSquare-4 50000000 35.3 ns/op PASS ok github.com/yoheiMune/MyGoProject/testtest 1.809s # ns/op:1オペレーションあたりの処理時間1回あたりの処理時間が35.3ナノ秒とわかります。単純な関数だけに高速ですね。
さらに
-benchmem
オプションを付与すると、メモリの使用状況も計測できます。$ go test -bench . -benchmem BenchmarkSquare-4 50000000 35.8 ns/op 0 B/op 0 allocs/op PASS ok github.com/yoheiMune/MyGoProject/testtest 1.835s # ns/op:1オペレーションあたりの処理時間 # B/op:1回あたりのアロケートで確保したメモリ量 # allocs/op:1回あたりのアロケート回数(=メモリ確保した回数)ここでは処理ごとにメモリ確保していないので高速だとわかります。メモリ確保はコストがかかる処理なので、回数や量は少ない方が良いです。
コンソールへの出力結果をテストする
さらに、go test
では、コンソールへの出力内容もテストすることができます。コンソール出力のテストの実装方法
関数名はExampleXXX
とし、引数なしでテスト関数を定義します。// Example系. func ExampleSquare() { v := Square(11) fmt.Println(v) // Output: 121 }コメントで
Output: 121
と書くことで、期待値を定義します。コンソール出力のテストを実行
テスト実行はgo test
で行います。$ go test PASS ok github.com/yoheiMune/MyGoProject/testtest 0.007s上記はテスト成功した場合の表示です(いつも通りですね)。
テスト失敗した場合には、以下のような表示になります。
// 「Output: 111」に書き換えてテストを実行 $ go test --- FAIL: ExampleSquare (0.00s) got: 121 want: 111 FAIL exit status 1 FAIL github.com/yoheiMune/MyGoProject/testtest 0.007s確かにExample系のテストが行われていることがわかります。
参考資料
Goのテストを学ぶのに、以下の記事を参照しました。ありがとうございます。Goのテストの基本と開発フロー // Speaker Deck
go標準のbenchmark機能の使い方 - Qiita
最後に
Go言語でもテストがいい感じにかけるのは素敵ですね。ただ、アサート処理が少し面倒で(assertEqualと書きたい)、それに対してtestifyというテストライブラリを使っている場合も多いです(Githubで公開されている他のライブラリのテストでもよく見かけます)。そちらも学んで、そのうちブログに書けたらと思います。最後になりますが本ブログでは、Go言語・Python・Linux・フロントエンド・Node.js・インフラ・開発環境・Swift・Java・機械学習など雑多に情報発信をしていきます。自分の第2の脳にすべく、情報をブログに貯めています。気になった方は、本ブログのRSSやTwitterをフォローして頂けると幸いです ^ ^。
最後までご覧頂きましてありがとうございました!