GO言語(golang)1.20をはじめる④:標準パッケージ(testing)でUNITTEST
目次
GO言語(golang)1.20をはじめる④:標準モジュール(testing)でUNITTEST
プログラムを書いたら、テストソースも書いてテストする。
こういうやり方が今は一般的です。
なので、テストソースの書き方も整理しておきます。
標準パッケージ「testing」
GO言語標準パッケージの「testing」を使います。
このパッケージの使い方にはルールがあります。
まずは、テストソースファイルの命名規則から
- テストソースはテスト対象ソースと同じ階層におく
- テストソースファイル名は、テスト対象ソース名に「_test」をつける
例えば。
helloフォルダの「hello.go」をテストするのであれば「hello_test.go」とします。
hello.goとhello_test.goは同じフォルダにおきます。
次に、テストソースの最低限の記述ルール。
- テストソースのパッケージ名はテスト対象ソースのパッケージと同じにする
- テスト関数は「Test]で始める
です。
こちらは、実際のソースで確認したほうが早いのでやってみます。
テスト対象とする簡単なソース
hello.goを以下のようにしました。
package main import ( "fmt" "math/rand" "time" ) func getAnswer(num int) string { var message string = "" switch { case num < 100: message = "二桁の数字です" case num < 200: message = "百から二百未満の数字です" default: message = "二百から三百未満の数字です" } return message } func main() { seed := time.Now().UnixNano() r := rand.New(rand.NewSource(seed)) fmt.Println(getAnswer(r.Intn(300))) }
これをテストするソースを書きます。
テストするソース
ポイントをおさらいします。
テストソースはテスト対象のソースとパッケージ名を同じにします。
今回の場合は元ソースと同じ「package main」です。
テスト対象のソースは「hello.go」なので、テストソースは「hello_test.go」です。
テストソースはテスト対象のソースと同じフォルダにおきます。
テスト関数は、Testを頭につけて「TestXxxx」のように大文字開始ではじめます。
そして「testing」をimportします。
そのルールを適用して書いたテストソースです。
package main import ( "testing" ) func TestGetAnswer01(t *testing.T) { result := getAnswer(99) if result != "1<=num<100" { t.Errorf("1<=num<100のところ%s", result) } result2 := getAnswer(1) if result2 != "1<=num<100" { t.Errorf("1<=num<100のところ%s", result2) } } func TestGetAnswer02(t *testing.T) { result := getAnswer(100) if result != "100<=num<200" { t.Errorf("100<=num<200のところ%s", result) } result2 := getAnswer(199) if result2 != "100<=num<200" { t.Errorf("100<=num<200のところ%s", result2) } } func TestGetAnswer03(t *testing.T) { result := getAnswer(200) if result != "200<=num<=300" { t.Errorf("200<=num<=300のところ%s", result) } result2 := getAnswer(300) if result2 != "200<=num<=300" { t.Errorf("200<=num<=300のところ%s", result2) } }
hello.goのローカル関数「getAnswer」をテストするコードになってます。
テストを実行する
上記の「hello_test.go」を「hello.go」と同じフォルダに置きます。
hello.go(mainパッケージ)のあるフォルダをカレントにして、以下を実行します。
go test ./...
すると、下位フォルダにサブモジュールを作り、そこにテストソースをおいていたとしても、まとめてテストを実行してくれます。
例えば、サブモジュール「greeting」があって、そこにはまだテストソースを置いてないと以下のような結果になります。
テストを実行してカバレッジを計測する
テストソースが、対象ソースをどれくらいカバーしているのか(カバレッジ)を計測することもできます。
カバレッジの計測をするだけなら以下のコマンドです。
go test -cover ./...
これで以下のような結果を表示してくれます。
でも、これだけだと「どこがカバレッジできてないのか」がわかりません。
その情報を得るには、まず、テストの実行を以下のコマンドに変えます。
go test -cover ./... -coverprofile=cover.out
これを実行すると、テスト結果は同じように表示され、カレントフォルダに「cover.out」というファイルができます。
それは以下のような内容です。
mode: set
boku/hello/hello.go:9.32,11.9 2 1
boku/hello/hello.go:12.17,13.25 1 1
boku/hello/hello.go:14.17,15.27 1 1
このファイルを読み込んでHTMLを作ります。
go tool cover -html=cover.out -o cover.html
これを実行すると、カレントフォルダに「cover.html」ができるので、それを開くと、ソースでカバレッジできていない部分を赤字で表示してくれます。
上記のテストソースだと、カバレッジは「66.7%」で、main()関数部分が、まるまるカバレッジできていないとなってます。
テストソースに以下を追加すると、カバレッジ100%にはなります。
func TestRunMain(t *testing.T) {
main()
}
このやり方が正解かどうかはわからないです。
ただ、main()はテストしづらいし、かといって放置するとカバレッジが気持ち悪いことになるので、僕はそうしてます。
とりあえず、最低限のテストのやり方だけ整理しました。
ではでは。