SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

GO言語(golang)1.20をはじめる④:標準パッケージ(testing)でUNITTEST

f:id:arakan_no_boku:20210412005751p:plain

目次

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()はテストしづらいし、かといって放置するとカバレッジが気持ち悪いことになるので、僕はそうしてます。

とりあえず、最低限のテストのやり方だけ整理しました。

ではでは。