これは、なにをしたくて書いたもの?
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) }