これは、なにをしたくて書いたもの?
Goでのテストの書き方を学んでみようかなと。
Goにはテストの仕組みが標準で組み込まれていて、go testコマンドとtestingパッケージを使うみたいです。
testing - The Go Programming Language
環境
今回の環境は、こちら。
$ go version go version go1.15.6 linux/amd64
testingパッケージ
testingパッケージは、Goでのテストをサポートするパッケージです。go testコマンドと組み合わせて使用します。
testing - The Go Programming Language
testingパッケージにはベンチマークも含まれているようですが、今回は扱いません。
また、ドキュメント以外にも、goコマンドのヘルプも見ておいた方が良いでしょう。ドキュメントにはない情報が
載っていたりします。
$ go help test $ go help testfunc
テストの条件
testingパッケージを使ってテストを書くには、以下のステップを踏みます。
- 名前が
_test.goで終わるファイルを作成する- テストするパッケージと同じパッケージに配置すること
- このファイルは、通常のビルドからは除外される
- ファイル名が
_または.で始まる場合は、無視される
- 関数名が
Testで始まる、テスト実行用の関数を作成するTestに続く文字は、小文字はNG- ○
TestSample、×Testsample
- ○
go testでテストを実行するtestdataディレクトリにテストデータを置くことができる
あとはTを使ってテストを書いていきます。
テスト結果はキャッシュされる模様。
また、Goにはアサーションの仕組みはないようです。
Frequently Asked Questions (FAQ) / Why does Go not have assertions?
まあ、とりあえず始めてみましょう。
準備
最初にモジュールを作っておきます。
$ go mod init testing-getting-started go: creating new go.mod: module testing-getting-started
パッケージを作って、その中に足し算、引き算を行う関数を作ります。
sample/calc.go
package sample func Plus(a int, b int) int { return a + b } func Minus(a int, b int) int { return a - b }
動作確認のためのソースコードも作りましょう。
main.go
package main import ( "fmt" "testing-getting-started/sample" ) func main() { fmt.Printf("1 + 3 = %d\n", sample.Plus(1, 3)) fmt.Printf("5 - 2 = %d\n", sample.Minus(5, 2)) }
確認。
$ go run main.go 1 + 3 = 4 5 - 2 = 3
これで、下準備はOKでしょう。
testingのAPIを触ってみる
とりあえず、testingのAPIを触ってみます。APIを知るために書いているので、ここではなにかの処理結果を確認したりはしません。
main_test.go
package main import ( "fmt" "testing" ) func TestSample(t *testing.T) { fmt.Println("Hello World!!") }
ドキュメントにあった通り、Testで始まる関数名にして、引数をTにします。
func TestSample(t *testing.T) {
確認。go testを実行します。
$ go test Hello World!! PASS ok testing-getting-started 0.001s
OKになりました。
-vフラグを使うと、もうちょっと詳細に見ることができます。
$ go test -v === RUN TestSample Hello World!! --- PASS: TestSample (0.00s) PASS ok testing-getting-started 0.001s
確かに、作成したテストが実行されているようです。
ところで、ファイル名が_や.で始まる場合は無視されるということでした。確認してみましょう。
ファイル名を変更。
$ mv main_test.go _main_test.go
確認。確かに無視されますね。
$ go test ? testing-getting-started [no test files] $ go test -v ? testing-getting-started [no test files]
元に戻しておきます。
$ mv _main_test.go main_test.go
テスト内では、Tに対するメソッドを使うようです。
以下のようなものがあります(全部ではありません)。
- Error / Errorf
- Fatal / Fatalf
- Fail / FailNow
- Log / Logf
- Skip / Skipf / SkipNow
- TempDir
Logを使ってみます。
main_test.go
package main import ( //"fmt" "testing" ) func TestSample(t *testing.T) { // fmt.Println("Hello World!!") t.Log("Hello Testing!!") }
go testではなにも出力されません。
$ go test PASS ok testing-getting-started 0.001s
-v付きで実行すると、ログが出力されます。
$ go test -v
=== RUN TestSample
main_test.go:11: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started 0.002s
続けて、Failを使ってみましょう。
Failを使うとテストが失敗します。
Failの呼び出しを追加して
func TestSample(t *testing.T) {
// fmt.Println("Hello World!!")
t.Log("Hello Testing!!")
t.Fail()
}
テストを実行すると、失敗します。
$ go test
--- FAIL: TestSample (0.00s)
main_test.go:11: Hello Testing!!
FAIL
exit status 1
FAIL testing-getting-started 0.001s
この時、よく見ると-vを付けていないのにLogの内容が出力されています。
ここで、Logの説明を読んでみると、
For tests, the text will be printed only if the test fails or the -test.v flag is set.
とあり、テストが失敗した時または-vフラグを付けてテストを実行した時に出力されるとあります。テストが問題ない時には
出さなくてもよい、ということですね。
ところで、Failに似たものとしてFailNowがあります。
2つの違いは、呼び出し後に継続するかどうかです。
Failの後に、ログを追加してみましょう。
func TestSample(t *testing.T) { // fmt.Println("Hello World!!") //t.Log("Hello Testing!!") t.Log("Test start") t.Fail() t.Log("Test end") }
確認。Failの後に記録したログも出力されています。
$ go test
--- FAIL: TestSample (0.00s)
main_test.go:13: Test start
main_test.go:17: Test end
FAIL
exit status 1
FAIL testing-getting-started 0.001s
では、FailをFailNowに変更してみます。
func TestSample(t *testing.T) { // fmt.Println("Hello World!!") //t.Log("Hello Testing!!") t.Log("Test start") //t.Fail() t.FailNow() t.Log("Test end") }
すると、FailNow呼び出し後のログは記録されなくなります。
$ go test
--- FAIL: TestSample (0.00s)
main_test.go:13: Test start
FAIL
exit status 1
FAIL testing-getting-started 0.002s
Nowが付くもの、付かないもの両方がある場合は、即時終了するのがNowで、そうでないものはそのまま継続するという
ことですね。
Skipは違うみたいですけどね…。
Skip is equivalent to Log followed by SkipNow.
ただ、実際にはFailやFailNowは使わず、ErrorやFatalを使うことになりそうですけどね。
先ほどのテストコードは、すっきりさせておきます。
main_test.go
package main import ( "testing" ) func TestSample(t *testing.T) { t.Log("Hello Testing!!") }
テストを書く
ここまでは、LogとかFailとかしか見てこなかったのですが、ここからは最初に用意した足し算、引き算に対するテストを
書いていきます。
テスト対象の関数はsampleパッケージに置いていたので、テストコードもsampleパッケージに配置します。
こんな感じで書いてみました。
sample/calc_test.go
package sample import ( "testing" ) func TestPlusGood(t *testing.T) { t.Logf("[Start %s]", t.Name()) expect := 3 if Plus(1, 2) != expect { t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, expect) } t.Logf("[End %s]", t.Name()) } func TestPlusBad(t *testing.T) { t.Logf("[Start %s]", t.Name()) expectBad := 4 if Plus(1, 2) != expectBad { // testcase miss t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, 3) } t.Logf("[End %s]", t.Name()) } func TestMinusGood(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expect := 2 if Minus(5, 3) != expect { t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, expect) } t.Logf("[End %s]", t.Name()) } func TestMinusBad(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expectBad := 3 if Minus(5, 3) != expectBad { // testcase miss t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, 2) } t.Logf("[End %s]", t.Name()) }
いきなり量が増えましたが、少しずつ見ていきます。それぞれ、成功するテスト、失敗するテストの2つずつを用意しています。
足し算の方は、こんな感じ。
func TestPlusGood(t *testing.T) { t.Logf("[Start %s]", t.Name()) expect := 3 if Plus(1, 2) != expect { t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, expect) } t.Logf("[End %s]", t.Name()) } func TestPlusBad(t *testing.T) { t.Logf("[Start %s]", t.Name()) expectBad := 4 if Plus(1, 2) != expectBad { // testcase miss t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, 3) } t.Logf("[End %s]", t.Name()) }
Logfというのは、Logに指定のフォーマットにしたものですね。Nameは、テストの名前を返します。
Fatalfというのは、フォーマットされたメッセージを与えつつテストを終了させるメソッドです。Fatalもあり、こちらは
単にメッセージを与えます。
引き算の方はFatalfをErrorfに変更して、あとShortを使っています。
func TestMinusGood(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expect := 2 if Minus(5, 3) != expect { t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, expect) } t.Logf("[End %s]", t.Name()) } func TestMinusBad(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expectBad := 3 if Minus(5, 3) != expectBad { // testcase miss t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, 2) } t.Logf("[End %s]", t.Name()) }
現時点で、このようなディレクトリ構成になっています。
$ tree
.
├── go.mod
├── main.go
├── main_test.go
└── sample
├── calc.go
└── calc_test.go
では、テストを実行してみます。
$ go test
PASS
ok testing-getting-started 0.002s
$ go test -v
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started 0.001s
どうやら、単にgo testとするだけではカレントディレクトリしか見てくれないようです。
そこでgo testの後に./...を付けると、サブディレクトリも見てくれるようになります。
ok testing-getting-started (cached)
--- FAIL: TestPlusBad (0.00s)
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestMinusBad (0.00s)
calc_test.go:52: [Start TestMinusBad]
calc_test.go:57: Minus(5, 3) should be 2, but doesn't match
calc_test.go:60: [End TestMinusBad]
FAIL
FAIL testing-getting-started/sample 0.002s
FAIL
## -v付き
$ go test ./... -v
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started (cached)
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestPlusBad
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestPlusBad (0.00s)
=== RUN TestMinusGood
calc_test.go:36: [Start TestMinusGood]
calc_test.go:44: [End TestMinusGood]
--- PASS: TestMinusGood (0.00s)
=== RUN TestMinusBad
calc_test.go:52: [Start TestMinusBad]
calc_test.go:57: Minus(5, 3) should be 2, but doesn't match
calc_test.go:60: [End TestMinusBad]
--- FAIL: TestMinusBad (0.00s)
FAIL
FAIL testing-getting-started/sample 0.002s
FAIL
なんとなく-vは./...の前に書きたい気もするのですが、この後いろいろフラグを書いていくと、パスは最初に書いた方がいいなぁと
思ってきました(書き換えるのはフラグの方が多そう)。
$ go test ./... -v
-vの方を見るとわかりますが、カレントディレクトリ+サブディレクトリになっていますね。
また、ErrorとFatal(使っているのはErrorfとFatalfですが)の違いもわかります。
足し算で失敗する方のテストはFatalfを使っていますが、Endが出力されていません。引き算の方はErrorfを使っていてEndまで
出力されています。
--- FAIL: TestPlusBad (0.00s)
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestMinusBad (0.00s)
calc_test.go:52: [Start TestMinusBad]
calc_test.go:57: Minus(5, 3) should be 2, but doesn't match
calc_test.go:60: [End TestMinusBad]
つまり、ErrorはLog+Fail、FatalはLog+FailNowです。説明にもそのように書いています。
あとは、Shortですね。これは、-shortフラグの指定有無を確認します。
引き算のテストは、Shortがtrueを返すとテストをスキップするように書いているので-short付きで実行すると、テストが
実行されません。
$ go test ./... -short
ok testing-getting-started (cached)
--- FAIL: TestPlusBad (0.00s)
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
FAIL
FAIL testing-getting-started/sample 0.002s
FAIL
-v付きで見ると、スキップされているのが確認できます。
$ go test ./... -short -v
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started (cached)
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestPlusBad
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestPlusBad (0.00s)
=== RUN TestMinusGood
calc_test.go:33: skip TestMinusGood!!
--- SKIP: TestMinusGood (0.00s)
=== RUN TestMinusBad
calc_test.go:49: skip TestMinusBad!!
--- SKIP: TestMinusBad (0.00s)
FAIL
FAIL testing-getting-started/sample 0.001s
FAIL
サブテストをまとめる
テスト用の関数内で、T#Runを呼び出すことでサブテストを作り、まとめることができます。
Using Subtests and Sub-benchmarks - The Go Blog
calc_test.goに、こんな感じで追加してみます。
func TestGrouped(t *testing.T) { t.Logf("[Group Test Start %s]", t.Name()) t.Run("TestPlus", func(t *testing.T) { t.Logf("[Start %s]", t.Name()) expect := 3 if Plus(1, 2) != expect { t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, expect) } t.Logf("[End %s]", t.Name()) }) t.Run("TestMinus", func(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expect := 2 if Minus(5, 3) != expect { t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, expect) } t.Logf("[End %s]", t.Name()) }) t.Logf("[Group Test End %s]", t.Name()) }
T#Runの引数としてサブテストの名前と、テストを行う関数を渡します。ここでは、テストを行う関数はその場で定義しています。
確認。
$ go test ./... -v
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started (cached)
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestPlusBad
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestPlusBad (0.00s)
=== RUN TestMinusGood
calc_test.go:36: [Start TestMinusGood]
calc_test.go:44: [End TestMinusGood]
--- PASS: TestMinusGood (0.00s)
=== RUN TestMinusBad
calc_test.go:52: [Start TestMinusBad]
calc_test.go:57: Minus(5, 3) should be 2, but doesn't match
calc_test.go:60: [End TestMinusBad]
--- FAIL: TestMinusBad (0.00s)
=== RUN TestGrouped
calc_test.go:64: [Group Test Start TestGrouped]
=== RUN TestGrouped/TestPlus
calc_test.go:67: [Start TestGrouped/TestPlus]
calc_test.go:75: [End TestGrouped/TestPlus]
=== RUN TestGrouped/TestMinus
calc_test.go:83: [Start TestGrouped/TestMinus]
calc_test.go:91: [End TestGrouped/TestMinus]
=== CONT TestGrouped
calc_test.go:94: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
--- PASS: TestGrouped/TestMinus (0.00s)
FAIL
FAIL testing-getting-started/sample 0.002s
FAIL
ここですね。
=== CONT TestGrouped
calc_test.go:94: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
--- PASS: TestGrouped/TestMinus (0.00s)
ちょっとわかりづらいですね。-runを使って実行するテストを絞り込んでみます。
サブテストを含むものだけ実行してみます。
$ go test ./... -run TestGrouped -v
testing: warning: no tests to run
PASS
ok testing-getting-started 0.004s [no tests to run]
=== RUN TestGrouped
calc_test.go:64: [Group Test Start TestGrouped]
=== RUN TestGrouped/TestPlus
calc_test.go:67: [Start TestGrouped/TestPlus]
calc_test.go:75: [End TestGrouped/TestPlus]
=== RUN TestGrouped/TestMinus
calc_test.go:83: [Start TestGrouped/TestMinus]
calc_test.go:91: [End TestGrouped/TestMinus]
=== CONT TestGrouped
calc_test.go:94: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
--- PASS: TestGrouped/TestMinus (0.00s)
PASS
ok testing-getting-started/sample 0.002s
サブテストを指定して実行することもできます。
$ go test ./... -run TestGrouped/TestPlus -v
testing: warning: no tests to run
PASS
ok testing-getting-started 0.002s [no tests to run]
=== RUN TestGrouped
calc_test.go:64: [Group Test Start TestGrouped]
=== RUN TestGrouped/TestPlus
calc_test.go:67: [Start TestGrouped/TestPlus]
calc_test.go:75: [End TestGrouped/TestPlus]
=== CONT TestGrouped
calc_test.go:94: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
PASS
ok testing-getting-started/sample 0.002s
通常のテストを指定することも可能ですし
$ go test ./... -run TestPlusGood -v
testing: warning: no tests to run
PASS
ok testing-getting-started (cached) [no tests to run]
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
PASS
ok testing-getting-started/sample (cached)
前方一致や
$ go test ./... -run TestPlus -v
testing: warning: no tests to run
PASS
ok testing-getting-started 0.002s [no tests to run]
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestPlusBad
calc_test.go:20: [Start TestPlusBad]
calc_test.go:25: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestPlusBad (0.00s)
FAIL
FAIL testing-getting-started/sample 0.003s
FAIL
正規表現の指定も可能です。
$ go test ./... -run 'Test(Plus|Minus)Good' -v
testing: warning: no tests to run
PASS
ok testing-getting-started 0.001s [no tests to run]
=== RUN TestPlusGood
calc_test.go:8: [Start TestPlusGood]
calc_test.go:16: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestMinusGood
calc_test.go:36: [Start TestMinusGood]
calc_test.go:44: [End TestMinusGood]
--- PASS: TestMinusGood (0.00s)
PASS
ok testing-getting-started/sample 0.002s
TestMain
TestMainを使うことで、パッケージ内のテストを始める前後になにかしらの処理を挟み込むことができます。
テスト関数単位ではなく、パッケージ単位です。
試してみましょう。importを追加。
import ( "fmt" "os" "testing" )
TestMainという名前で、Mを引数に取る関数を定義します。TestMain以外の名前にしてはいけません。
func TestMain(m *testing.M) { fmt.Println("[Start TestMain]") ret := m.Run() fmt.Printf("[End TestMain] ret = %d\n", ret) os.Exit(ret) }
また、M#Runの呼び出しを忘れると、そのパッケージ内のテストが実行されないことにも注意です。
Tが使えないのでLogも使えません。今回はfmt#Printlnを使ってログ出力し、この時にM#Runの戻り値を出力してみましょう。
確認。
$ go test ./... -v
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started (cached)
[Start TestMain]
=== RUN TestPlusGood
calc_test.go:10: [Start TestPlusGood]
calc_test.go:18: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestPlusBad
calc_test.go:22: [Start TestPlusBad]
calc_test.go:27: Plus(1, 2) should be 3, but doesn't match
--- FAIL: TestPlusBad (0.00s)
=== RUN TestMinusGood
calc_test.go:38: [Start TestMinusGood]
calc_test.go:46: [End TestMinusGood]
--- PASS: TestMinusGood (0.00s)
=== RUN TestMinusBad
calc_test.go:54: [Start TestMinusBad]
calc_test.go:59: Minus(5, 3) should be 2, but doesn't match
calc_test.go:62: [End TestMinusBad]
--- FAIL: TestMinusBad (0.00s)
=== RUN TestGrouped
calc_test.go:66: [Group Test Start TestGrouped]
=== RUN TestGrouped/TestPlus
calc_test.go:69: [Start TestGrouped/TestPlus]
calc_test.go:77: [End TestGrouped/TestPlus]
=== RUN TestGrouped/TestMinus
calc_test.go:85: [Start TestGrouped/TestMinus]
calc_test.go:93: [End TestGrouped/TestMinus]
=== CONT TestGrouped
calc_test.go:96: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
--- PASS: TestGrouped/TestMinus (0.00s)
FAIL
[End TestMain] ret = 1
FAIL testing-getting-started/sample 0.002s
FAIL
よーく見ると、パッケージ内のテスト開始前後にログが追加されています。
[Start TestMain]
=== RUN TestPlusGood
calc_test.go:10: [Start TestPlusGood]
calc_test.go:18: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
...
=== CONT TestGrouped
calc_test.go:96: [Group Test End TestGrouped]
--- PASS: TestGrouped (0.00s)
--- PASS: TestGrouped/TestPlus (0.00s)
--- PASS: TestGrouped/TestMinus (0.00s)
FAIL
[End TestMain] ret = 1
トップレベルの方に変化はありませんね。TestMainがないからです。
=== RUN TestSample
main_test.go:8: Hello Testing!!
--- PASS: TestSample (0.00s)
PASS
ok testing-getting-started (cached)
戻り値に関してですが、成功するテストに絞ってみましょう。
$ go test ./... -run 'Test(Plus|Minus)Good' -v
testing: warning: no tests to run
PASS
ok testing-getting-started (cached) [no tests to run]
[Start TestMain]
=== RUN TestPlusGood
calc_test.go:10: [Start TestPlusGood]
calc_test.go:18: [End TestPlusGood]
--- PASS: TestPlusGood (0.00s)
=== RUN TestMinusGood
calc_test.go:38: [Start TestMinusGood]
calc_test.go:46: [End TestMinusGood]
--- PASS: TestMinusGood (0.00s)
PASS
[End TestMain] ret = 0
ok testing-getting-started/sample (cached)
戻り値が0になりました。
[End TestMain] ret = 0
とりあえず、こんなところでしょうか。
オマケ
最後に、ディレクトリツリーと書いたテストコードの全体を載せておきます。
$ tree
.
├── go.mod
├── main.go
├── main_test.go
└── sample
├── calc.go
└── calc_test.go
sample/calc_test.go
package sample import ( "fmt" "os" "testing" ) func TestPlusGood(t *testing.T) { t.Logf("[Start %s]", t.Name()) expect := 3 if Plus(1, 2) != expect { t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, expect) } t.Logf("[End %s]", t.Name()) } func TestPlusBad(t *testing.T) { t.Logf("[Start %s]", t.Name()) expectBad := 4 if Plus(1, 2) != expectBad { // testcase miss t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, 3) } t.Logf("[End %s]", t.Name()) } func TestMinusGood(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expect := 2 if Minus(5, 3) != expect { t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, expect) } t.Logf("[End %s]", t.Name()) } func TestMinusBad(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expectBad := 3 if Minus(5, 3) != expectBad { // testcase miss t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, 2) } t.Logf("[End %s]", t.Name()) } func TestGrouped(t *testing.T) { t.Logf("[Group Test Start %s]", t.Name()) t.Run("TestPlus", func(t *testing.T) { t.Logf("[Start %s]", t.Name()) expect := 3 if Plus(1, 2) != expect { t.Fatalf("Plus(%d, %d) should be %d, but doesn't match", 1, 2, expect) } t.Logf("[End %s]", t.Name()) }) t.Run("TestMinus", func(t *testing.T) { if testing.Short() { t.Skipf("skip %s!!", t.Name()) } t.Logf("[Start %s]", t.Name()) expect := 2 if Minus(5, 3) != expect { t.Errorf("Minus(%d, %d) should be %d, but doesn't match", 5, 3, expect) } t.Logf("[End %s]", t.Name()) }) t.Logf("[Group Test End %s]", t.Name()) } func TestMain(m *testing.M) { fmt.Println("[Start TestMain]") ret := m.Run() fmt.Printf("[End TestMain] ret = %d\n", ret) os.Exit(ret) }