これは、なにをしたくて書いたもの?
Goにおける、アサーションなどの機能を提供するtestifyというライブラリがあるのを知りまして。
こちらを少し試しておきたいな、と。
testify
testifyは、以下の機能を提供するライブラリです。
- アサーション
- モック
- テストスイート向けの機能
testingパッケージを使い、go testでテストをするというのは通常のGoのテストと変わりません。
testing - The Go Programming Language
APIドキュメントはこちら。
今回は、アサーションとテストスイート向けの機能を試していきたいと思います。
環境
今回の環境は、こちら。
$ go version go version go1.15.6 linux/amd64
モジュールの作成。
$ go mod init testify-assert-example go: creating new go.mod: module testify-assert-example
testifyは、1.6.1を使います。
go.mod
module testify-assert-example go 1.15 require github.com/stretchr/testify v1.6.1
go.sum
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
お題
アサーションはけっこうな数があるので、それをひとつひとつ試していくようなことはしません。どちらかというと、
ライブラリの使い方の雰囲気、全体感を把握したいな、と。
というわけで、テスト対象のソースコードはこれだけにします。
calc.go
package main func Plus(a int, b int) int { return a + b }
assertパッケージ
まずは、アサーションからです。testifyのassertというパッケージを使います。
assertパッケージは、以下の機能を持ちます。
assertパッケージを使ったテストコードは、こんな感じで作成しました。
calc_test.go
package main import ( "github.com/stretchr/testify/assert" "testing" ) func TestPlusSimply(t *testing.T) { result := Plus(1, 3) expect := 4 assert.Equal(t, expect, result) } func TestPlusAssertFailContinue(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 assert.Equal(t, expect1, result1) result2 := Plus(1, 3) badExpect2 := 5 // miss assert.Equal(t, badExpect2, result2) result3 := Plus(3, 5) expect3 := 8 assert.Equal(t, expect3, result3, "not equal") result4 := Plus(3, 5) badExpect4 := 9 // miss assert.Equal(t, badExpect4, result4, "not equal") } func TestPlusFormat(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 assert.Equalf(t, expect1, result1, "not equal, collect = %d", expect1) result2 := Plus(1, 3) badExpect2 := 5 // miss assert.Equalf(t, badExpect2, result2, "not equal, collect = %d", 4) result3 := Plus(3, 5) expect3 := 8 assert.Equalf(t, expect3, result3, "not equal, collect = %d", expect3) result4 := Plus(3, 5) badExpect4 := 9 // miss assert.Equalf(t, badExpect4, result4, "not equal, collect = %d", 8) }
説明していきます。
最低限、testingとtestify/assertの2つが必要です。
import ( "github.com/stretchr/testify/assert" "testing" )
使い方としては、assert.[使いたいアサーション関数]となります。
func TestPlusSimply(t *testing.T) {
result := Plus(1, 3)
expect := 4
assert.Equal(t, expect, result)
}
最初の引数にtestingのT、あとは期待値、実際の値という順で書いていきます。
今回使っているのは、期待値と実際の値が等しいことを確認するEqualですね。
ちなみに、戻り値としてはboolが返ってきます…。
4番目の引数としてカスタムメッセージを入れると、失敗時にメッセージを入れることができます。
以下では、後ろの2つにメッセージを入れました。
func TestPlusAssertFailContinue(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 assert.Equal(t, expect1, result1) result2 := Plus(1, 3) badExpect2 := 5 // miss assert.Equal(t, badExpect2, result2) result3 := Plus(3, 5) expect3 := 8 assert.Equal(t, expect3, result3, "not equal") result4 := Plus(3, 5) badExpect4 := 9 // miss assert.Equal(t, badExpect4, result4, "not equal") }
このテストでは、意図的に失敗するテストを書いています。テストを実行すると、こんな感じになります。
$ go test
--- FAIL: TestPlusAssertFailContinue (0.00s)
--- FAIL: TestPlusAssertFailContinue (0.00s)
calc_test.go:24:
Error Trace: calc_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusAssertFailContinue
calc_test.go:34:
Error Trace: calc_test.go:34
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusAssertFailContinue
Messages: not equal
カスタムメッセージを指定した方には、Messagesという項目が追加されます。
が、これを見たらわかるように、-vを付けなくても十分に情報が出ます。
-vを付けると、こんな感じになります。
=== RUN TestPlusAssertFailContinue
calc_test.go:24:
Error Trace: calc_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusAssertFailContinue
calc_test.go:34:
Error Trace: calc_test.go:34
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusAssertFailContinue
Messages: not equal
--- FAIL: TestPlusAssertFailContinue (0.00s)
この時点でわかりますが、assertを使ってアサーションに失敗した場合、テストには失敗しますがテスト自体は続行します。
testingのErrorの挙動ですね。
実際、assertパッケージの各関数はErrorを使って作成されています。
https://github.com/stretchr/testify/blob/v1.6.1/assert/assertions.go#L240-L265
また、末尾がfの方の関数を使うと、カスタムメッセージのフォーマットが指定できることになっています。
func TestPlusFormat(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 assert.Equalf(t, expect1, result1, "not equal, collect = %d", expect1) result2 := Plus(1, 3) badExpect2 := 5 // miss assert.Equalf(t, badExpect2, result2, "not equal, collect = %d", 4) result3 := Plus(3, 5) expect3 := 8 assert.Equalf(t, expect3, result3, "not equal, collect = %d", expect3) result4 := Plus(3, 5) badExpect4 := 9 // miss assert.Equalf(t, badExpect4, result4, "not equal, collect = %d", 8) }
実行結果。
--- FAIL: TestPlusFormat (0.00s)
calc_test.go:46:
Error Trace: calc_test.go:46
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusFormat
Messages: not equal, collect = 4
calc_test.go:56:
Error Trace: calc_test.go:56
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusFormat
Messages: not equal, collect = 8
なんですが、fなしのアサーション関数でも、フォーマットは使えるっぽいですが…?
最終的には、fmt#Sprintfが使われるからですね。
https://github.com/stretchr/testify/blob/v1.6.1/assert/assertions.go#L191
testingとかと合わせるなら、フォーマットを指定する場合はf付きの方を使うのが無難でしょうか。
とまあ、雰囲気はこんな感じみたいです。その他のアサーション用の関数については、APIドキュメントを眺めましょう。
最後に、テスト実行結果の全体を貼っておきます。
$ go test
--- FAIL: TestPlusAssertFailContinue (0.00s)
calc_test.go:24:
Error Trace: calc_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusAssertFailContinue
calc_test.go:34:
Error Trace: calc_test.go:34
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusAssertFailContinue
Messages: not equal
--- FAIL: TestPlusFormat (0.00s)
calc_test.go:46:
Error Trace: calc_test.go:46
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusFormat
Messages: not equal, collect = 4
calc_test.go:56:
Error Trace: calc_test.go:56
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusFormat
Messages: not equal, collect = 8
FAIL
exit status 1
FAIL testify-assert-example 0.003s
## -v付き
$ go test -v
=== RUN TestPlusSimply
--- PASS: TestPlusSimply (0.00s)
=== RUN TestPlusAssertFailContinue
calc_test.go:24:
Error Trace: calc_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusAssertFailContinue
calc_test.go:34:
Error Trace: calc_test.go:34
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusAssertFailContinue
Messages: not equal
--- FAIL: TestPlusAssertFailContinue (0.00s)
=== RUN TestPlusFormat
calc_test.go:46:
Error Trace: calc_test.go:46
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusFormat
Messages: not equal, collect = 4
calc_test.go:56:
Error Trace: calc_test.go:56
Error: Not equal:
expected: 9
actual : 8
Test: TestPlusFormat
Messages: not equal, collect = 8
--- FAIL: TestPlusFormat (0.00s)
FAIL
exit status 1
FAIL testify-assert-example 0.002s
この後、別のtestifyパッケージを付けるので、このテストファイルはリネームしておきます。
$ mv calc_test.go _calc_test.go
requireパッケージ
assertパッケージの次は、requireパッケージについて。
こちらは、assertパッケージと使い方が非常によく似ています。
assertと書いていたところをrequireにすると、ほぼ置き換えられます。以下は、先ほどのassertパッケージを使った
テストコードをrequireパッケージに置換してテスト関数名を少し変更したものです。
calc_require_test.go
package main import ( "github.com/stretchr/testify/require" "testing" ) func TestPlusSimplyUsingRequire(t *testing.T) { result := Plus(1, 3) expect := 4 require.Equal(t, expect, result) } func TestPlusRequireFailContinueUsingRequire(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 require.Equal(t, expect1, result1) result2 := Plus(1, 3) badExpect2 := 5 // miss require.Equal(t, badExpect2, result2) result3 := Plus(3, 5) expect3 := 8 require.Equal(t, expect3, result3, "not equal") result4 := Plus(3, 5) badExpect4 := 9 // miss require.Equal(t, badExpect4, result4, "not equal") } func TestPlusFormatUsingRequire(t *testing.T) { result1 := Plus(1, 3) expect1 := 4 require.Equalf(t, expect1, result1, "not equal, collect = %d", expect1) result2 := Plus(1, 3) badExpect2 := 5 // miss require.Equalf(t, badExpect2, result2, "not equal, collect = %d", 4) result3 := Plus(3, 5) expect3 := 8 require.Equalf(t, expect3, result3, "not equal, collect = %d", expect3) result4 := Plus(3, 5) badExpect4 := 9 // miss require.Equalf(t, badExpect4, result4, "not equal, collect = %d", 8) }
実行結果。
$ go test
--- FAIL: TestPlusRequireFailContinueUsingRequire (0.00s)
calc_require_test.go:24:
Error Trace: calc_require_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusRequireFailContinueUsingRequire
--- FAIL: TestPlusFormatUsingRequire (0.00s)
calc_require_test.go:46:
Error Trace: calc_require_test.go:46
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusFormatUsingRequire
Messages: not equal, collect = 4
FAIL
exit status 1
FAIL testify-assert-example 0.002s
## -v付き
$ go test -v
=== RUN TestPlusSimplyUsingRequire
--- PASS: TestPlusSimplyUsingRequire (0.00s)
=== RUN TestPlusRequireFailContinueUsingRequire
calc_require_test.go:24:
Error Trace: calc_require_test.go:24
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusRequireFailContinueUsingRequire
--- FAIL: TestPlusRequireFailContinueUsingRequire (0.00s)
=== RUN TestPlusFormatUsingRequire
calc_require_test.go:46:
Error Trace: calc_require_test.go:46
Error: Not equal:
expected: 5
actual : 4
Test: TestPlusFormatUsingRequire
Messages: not equal, collect = 4
--- FAIL: TestPlusFormatUsingRequire (0.00s)
FAIL
exit status 1
FAIL testify-assert-example 0.003s
assertパッケージとの違いは、次の2つです。
- 戻り値がない
- アサーションに失敗すると、テスト関数が即終了する
なので、先ほどのassertパッケージを使ったテストコードと違い、アサーションに失敗した時点で後続のアサーションの呼び出しは
行われず、後続でエラーになるはずのアサーションの記録も残っていません。
これは、requireの中身を見るとわかりますが、内部的にはassertを呼び出し、アサーションに失敗するとtestingのT#FailNowを
呼び出すようになっているからです。
https://github.com/stretchr/testify/blob/v1.6.1/require/require.go
さらに言うと、requireパッケージはassertパッケージを使って自動生成されるようになっています。
https://github.com/stretchr/testify/blob/v1.6.1/require/require.go#L1-L4
https://github.com/stretchr/testify/blob/v1.6.1/_codegen/main.go#L31-L35
https://github.com/stretchr/testify/blob/v1.6.1/require/require.go.tmpl
なので、assertパッケージとほぼ同じことができる、というわけですね。
このファイルも、後続のテストのジャマにならないようにリネームしておきます。
$ mv calc_require_test.go _calc_require_test.go
suiteパッケージ
最後はsuiteパッケージです。suiteパッケージを使用すると、オブジェクト指向言語に似た形でテストの際にSetUpやTearDown
ということを行えます。
これは、実際に書いていった方がいいでしょう。
最小構成は、こんな感じでしょうか。ここでは、最初に作ったcalc.goは無視しました…。
calc_suite_test.go
package main import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "testing" ) type MyTestSuiteStruct struct { suite.Suite } func (suite *MyTestSuiteStruct) TestHello() { assert.Equal(suite.T(), 1, 1) } func TestFirstTestSuite(t *testing.T) { suite.Run(t, new(MyTestSuiteStruct)) }
とりあえず、suiteパッケージはimportするとして
import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "testing" )
最初に、suite#Suiteを埋め込んだ構造体を定義します。
type MyTestSuiteStruct struct { suite.Suite }
テスト関数を作成し、suite#Runにtesting#Tと定義した構造体を初期化して渡します。
func TestFirstTestSuite(t *testing.T) { suite.Run(t, new(MyTestSuiteStruct)) }
あとは、定義した構造体をレシーバーとするメソッドを定義していきます。メソッド名は、Testで始めてください。
func (suite *MyTestSuiteStruct) TestHello() { assert.Equal(suite.T(), 1, 1) }
アサーションは、今回はassertパッケージを使いました。assertを使うにはtesting#Tが必要ですが、これはsuite#Tで
取得できます。
また、suite#Assertを使ってもOKです。同じ理屈で、suite#Requireも使えます。
実行結果。
$ go test
PASS
ok testify-assert-example 0.003s
## -v付き
$ go test -v
=== RUN TestFirstTestSuite
=== RUN TestFirstTestSuite/TestHello
--- PASS: TestFirstTestSuite (0.00s)
--- PASS: TestFirstTestSuite/TestHello (0.00s)
PASS
ok testify-assert-example 0.003s
テスト用のメソッドが、最初に定義したテスト関数のサブテストのような形態で実行されていますね。
これをまとめている単位が、テストスイートなのでしょうね。
ひとつ、テストメソッドを足してみましょう。これは、失敗するテストです。
func (suite *MyTestSuiteStruct) TestBool() { assert.True(suite.T(), false) }
確認。
$ go test -v
=== RUN TestFirstTestSuite
=== RUN TestFirstTestSuite/TestBool
calc_suite_test.go:18:
Error Trace: calc_suite_test.go:18
Error: Should be true
Test: TestFirstTestSuite/TestBool
=== RUN TestFirstTestSuite/TestHello
--- FAIL: TestFirstTestSuite (0.00s)
--- FAIL: TestFirstTestSuite/TestBool (0.00s)
--- PASS: TestFirstTestSuite/TestHello (0.00s)
FAIL
exit status 1
FAIL testify-assert-example 0.003s
テスト関数内に、ひとつテストが追加されました。
この状態で、実行するテストメソッドを-runでコントロールすることもできるみたいですね。
$ go test -run TestFirstTestSuite/TestHello -v
=== RUN TestFirstTestSuite
=== RUN TestFirstTestSuite/TestHello
--- PASS: TestFirstTestSuite (0.00s)
--- PASS: TestFirstTestSuite/TestHello (0.00s)
PASS
ok testify-assert-example 0.003s
次に、テストの前後にメソッド呼び出しを挟んでみましょう。
テストの前後にメソッド呼び出しを追加する場合は、指定のインターフェースに定義されたメソッドを実装します。
このあたりですね。
- type SetupAllSuite
- type SetupTestSuite
- type BeforeTest
- type AfterTest
- type TearDownTestSuite
- type TearDownAllSuite
どのインターフェースに定義されたメソッドを実装するかで、呼び出しタイミングが変わります。
なお、インターフェース名がメソッド名っぽいですが、実装すべきメソッド名と必ずしも一致していないので、どのメソッドを
実装すべきかはちゃんと定義を見た方がいいです…。
今回はテスト単位の前後に入れてみましょう。この目的の場合、SetupTestSuiteとBeforeTest、AfterTestとTearDownTestSuiteが
使えるのですが、今回はBeforeTestとAfterTestを使いましょう。
こんな感じです。
func (suite *MyTestSuiteStruct) BeforeTest(suiteName string, testName string) { suite.T().Log("BeforeTest!!") } func (suite *MyTestSuiteStruct) AfterTest(suiteName string, testName string) { suite.T().Log("AfterTest!!") } func (suite *MyTestSuiteStruct) TestHello() { suite.T().Log("run TestHello!!") assert.Equal(suite.T(), 1, 1) } func (suite *MyTestSuiteStruct) TestBool() { suite.T().Log("run TestBool!!") assert.True(suite.T(), false) }
BeforeTest、AfterTestともに、引数にテストスイート名とテスト名を取ります。
今回は呼び出しタイミングがわかりやすいようにログ出力してみました。
確認。
$ go test -v
=== RUN TestFirstTestSuite
=== RUN TestFirstTestSuite/TestBool
calc_suite_test.go:14: BeforeTest!!
calc_suite_test.go:27: run TestBool!!
calc_suite_test.go:28:
Error Trace: calc_suite_test.go:28
Error: Should be true
Test: TestFirstTestSuite/TestBool
calc_suite_test.go:18: AfterTest!!
=== RUN TestFirstTestSuite/TestHello
calc_suite_test.go:14: BeforeTest!!
calc_suite_test.go:22: run TestHello!!
calc_suite_test.go:18: AfterTest!!
--- FAIL: TestFirstTestSuite (0.00s)
--- FAIL: TestFirstTestSuite/TestBool (0.00s)
--- PASS: TestFirstTestSuite/TestHello (0.00s)
FAIL
exit status 1
FAIL testify-assert-example 0.003s
こんな感じで、テスト前後に呼び出しが入っているのが確認できます。
また、テストスイートを定義する際の構造体は、埋め込んだsuite.Suite以外にもメンバーを持つことができます。
type SampleTestStruct struct { suite.Suite ExecutedTestMethodNames []string CallSetupSuiteCount int CallSetupTestCount int CallBeforeTestCounts map[string]int runTestMethodNames []string CallAfterTestCounts map[string]int CallTearDownTestCount int CallTearDownSuiteCount int }
先ほど書いたサンプルとは別に、もうひとつテストスイートを起こしてみましょう。今回は、テストの前後に実行できるメソッドを
すべて実装します。
calc_suite2_test.go
package main import ( "encoding/json" "fmt" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" "testing" ) type SampleTestStruct struct { suite.Suite ExecutedTestMethodNames []string CallSetupSuiteCount int CallSetupTestCount int CallBeforeTestCounts map[string]int runTestMethodNames []string CallAfterTestCounts map[string]int CallTearDownTestCount int CallTearDownSuiteCount int } func (suite *SampleTestStruct) SetupSuite() { suite.T().Logf("===== SetupSuite =====") suite.CallSetupSuiteCount += 1 } func (suite *SampleTestStruct) SetupTest() { suite.T().Logf("===== SetupTest =====") suite.CallSetupTestCount += 1 } func (suite *SampleTestStruct) BeforeTest(suiteName string, testName string) { suite.T().Logf("===== BeforeTest suite[%s] test[%s] =====", suiteName, testName) if suite.CallBeforeTestCounts == nil { suite.CallBeforeTestCounts = make(map[string]int) } suite.CallBeforeTestCounts[suiteName+"/"+testName] += 1 } func (suite *SampleTestStruct) AfterTest(suiteName string, testName string) { suite.T().Logf("===== AfterTest suite[%s] test[%s] =====", suiteName, testName) if suite.CallAfterTestCounts == nil { suite.CallAfterTestCounts = make(map[string]int) } suite.CallAfterTestCounts[suiteName+"/"+testName] += 1 } func (suite *SampleTestStruct) TearDownTest() { suite.T().Logf("===== TearDownTest =====") suite.CallTearDownTestCount += 1 } func (suite *SampleTestStruct) TearDownSuite() { suite.T().Logf("===== TearDownSuite =====") suite.CallTearDownSuiteCount += 1 beforeTestCounts, _ := json.Marshal(suite.CallBeforeTestCounts) afterTestCounts, _ := json.Marshal(suite.CallAfterTestCounts) runTestMethodNames, _ := json.Marshal(suite.runTestMethodNames) fmt.Printf(`---------------------------------------------------------------------- SetupSuiteCount = %d SetupTestCount = %d BeforeTestCounts = ( %s ) runTestMethods = %s AfterTestCounts = ( %s ) TearDownTestCount = %d TearDownSuiteCount = %d ---------------------------------------------------------------------- `, suite.CallSetupSuiteCount, suite.CallSetupTestCount, beforeTestCounts, runTestMethodNames, afterTestCounts, suite.CallTearDownTestCount, suite.CallTearDownSuiteCount, ) } func (suite *SampleTestStruct) TestPlus() { suite.T().Logf("run %s", suite.T().Name()) if suite.runTestMethodNames == nil { suite.runTestMethodNames = make([]string, 0) } suite.runTestMethodNames = append(suite.runTestMethodNames, suite.T().Name()) assert.Equal(suite.T(), 1, 1) } func (suite *SampleTestStruct) TestBool() { suite.T().Logf("run %s", suite.T().Name()) if suite.runTestMethodNames == nil { suite.runTestMethodNames = make([]string, 0) } suite.runTestMethodNames = append(suite.runTestMethodNames, suite.T().Name()) assert.True(suite.T(), true) } func TestSuiteExample(t *testing.T) { suite.Run(t, new(SampleTestStruct)) }
構造体には、メソッド呼び出し時にそのタイミングに応じたカウンターを設け、記録していくようにしました。
type SampleTestStruct struct { suite.Suite ExecutedTestMethodNames []string CallSetupSuiteCount int CallSetupTestCount int CallBeforeTestCounts map[string]int runTestMethodNames []string CallAfterTestCounts map[string]int CallTearDownTestCount int CallTearDownSuiteCount int }
結果。2つのテストスイートを実行しました。
$ go test -v
=== RUN TestSuiteExample
calc_suite2_test.go:26: ===== SetupSuite =====
=== RUN TestSuiteExample/TestBool
calc_suite2_test.go:31: ===== SetupTest =====
calc_suite2_test.go:36: ===== BeforeTest suite[SampleTestStruct] test[TestBool] =====
calc_suite2_test.go:105: run TestSuiteExample/TestBool
calc_suite2_test.go:46: ===== AfterTest suite[SampleTestStruct] test[TestBool] =====
calc_suite2_test.go:56: ===== TearDownTest =====
=== RUN TestSuiteExample/TestPlus
calc_suite2_test.go:31: ===== SetupTest =====
calc_suite2_test.go:36: ===== BeforeTest suite[SampleTestStruct] test[TestPlus] =====
calc_suite2_test.go:93: run TestSuiteExample/TestPlus
calc_suite2_test.go:46: ===== AfterTest suite[SampleTestStruct] test[TestPlus] =====
calc_suite2_test.go:56: ===== TearDownTest =====
=== CONT TestSuiteExample
calc_suite2_test.go:61: ===== TearDownSuite =====
----------------------------------------------------------------------
SetupSuiteCount = 1
SetupTestCount = 2
BeforeTestCounts = (
{"SampleTestStruct/TestBool":1,"SampleTestStruct/TestPlus":1}
)
runTestMethods = ["TestSuiteExample/TestBool","TestSuiteExample/TestPlus"]
AfterTestCounts = (
{"SampleTestStruct/TestBool":1,"SampleTestStruct/TestPlus":1}
)
TearDownTestCount = 2
TearDownSuiteCount = 1
----------------------------------------------------------------------
--- PASS: TestSuiteExample (0.00s)
--- PASS: TestSuiteExample/TestBool (0.00s)
--- PASS: TestSuiteExample/TestPlus (0.00s)
=== RUN TestFirstTestSuite
=== RUN TestFirstTestSuite/TestBool
calc_suite_test.go:14: BeforeTest!!
calc_suite_test.go:27: run TestBool!!
calc_suite_test.go:28:
Error Trace: calc_suite_test.go:28
Error: Should be true
Test: TestFirstTestSuite/TestBool
calc_suite_test.go:18: AfterTest!!
=== RUN TestFirstTestSuite/TestHello
calc_suite_test.go:14: BeforeTest!!
calc_suite_test.go:22: run TestHello!!
calc_suite_test.go:18: AfterTest!!
--- FAIL: TestFirstTestSuite (0.00s)
--- FAIL: TestFirstTestSuite/TestBool (0.00s)
--- PASS: TestFirstTestSuite/TestHello (0.00s)
FAIL
exit status 1
FAIL testify-assert-example 0.004s
追加した方のテストスイートの表示は、こちらですね。
=== RUN TestSuiteExample
calc_suite2_test.go:26: ===== SetupSuite =====
=== RUN TestSuiteExample/TestBool
calc_suite2_test.go:31: ===== SetupTest =====
calc_suite2_test.go:36: ===== BeforeTest suite[SampleTestStruct] test[TestBool] =====
calc_suite2_test.go:105: run TestSuiteExample/TestBool
calc_suite2_test.go:46: ===== AfterTest suite[SampleTestStruct] test[TestBool] =====
calc_suite2_test.go:56: ===== TearDownTest =====
=== RUN TestSuiteExample/TestPlus
calc_suite2_test.go:31: ===== SetupTest =====
calc_suite2_test.go:36: ===== BeforeTest suite[SampleTestStruct] test[TestPlus] =====
calc_suite2_test.go:93: run TestSuiteExample/TestPlus
calc_suite2_test.go:46: ===== AfterTest suite[SampleTestStruct] test[TestPlus] =====
calc_suite2_test.go:56: ===== TearDownTest =====
=== CONT TestSuiteExample
calc_suite2_test.go:61: ===== TearDownSuite =====
----------------------------------------------------------------------
SetupSuiteCount = 1
SetupTestCount = 2
BeforeTestCounts = (
{"SampleTestStruct/TestBool":1,"SampleTestStruct/TestPlus":1}
)
runTestMethods = ["TestSuiteExample/TestBool","TestSuiteExample/TestPlus"]
AfterTestCounts = (
{"SampleTestStruct/TestBool":1,"SampleTestStruct/TestPlus":1}
)
TearDownTestCount = 2
TearDownSuiteCount = 1
----------------------------------------------------------------------
これで、テストの実行タイミングが確認できると思います。
一応、メソッドと実行タイミングの対応を書くと、以下のようになります。
| メソッド名 | 実行タイミング |
|---|---|
| SetupSuite | テストスイートの実行前 |
| SetupTest | (テストスイート内の)各テストメソッドの実行前 |
| BeforeTest | (テストスイート内の)各テストメソッドの実行前 |
| AfterTest | (テストスイート内の)各テストメソッドの実行後 |
| TearDownTest | (テストスイート内の)各テストメソッドの実行後 |
| TearDownSuite | テストスイートの実行後 |
SetupTestとBeforeTest、AfterTestとTearDownTestの違いは、引数の有無と考えればよさそうです。
このあたりの、テストメソッドと前後に入れ込むメソッドの実行タイミングの定義は以下を確認すると良いでしょう。
https://github.com/stretchr/testify/blob/v1.6.1/suite/suite.go#L112-L176
また、テストスイートのグルーピングの単位がsuite#Suiteを埋め込んだ構造体であることも確認できましたね。
あと、suiteパッケージの使い方としては、こちらを見てもよいでしょう。
https://github.com/stretchr/testify/blob/v1.6.1/suite/suite_test.go
まとめ
testifyのassert(とrequire)、suiteに関してちょっと試してみました。
まだGo自体に慣れないので、suiteの使い方は特に手間取ったのですが、testifyのソースコードもそれほど大きくなかったので
Goを読む勉強としても良かったです。