#はじめに
「Go言語で単体テストってどうやって書くの??」
調べてみたので、まとめてみました。
Golangの標準パッケージtesting
を使用すると、単体テストを書くことができます。
#testing
testing
では、_test.go
のようにテストファイルを作成します。
テストコードは、TestXxx
と記載し、Xxxについてのテストを実行します。
テストコードを対応するソースコードと同一のパッケージにすることで、privateな変数や関数を呼び出すことができます。 APIを必要以上公開せずにテストを書くことができます。
#testify
標準パッケージのtesting
にはassert関数はありません。
testify
ライブラリーを使用することで、assert関数を使うことができます。
使用する場合は、下記のようにインストールしてください。
$ go get -u -v github.com/stretchr/testify
#テストの例
例としてuser.go
のテストを、user_test.go
として作成してみました。
package user
type User struct {
ID int64
Name String
Email String
}
func NewUser(id int64, name string, email string) *User {
return &User{
ID: id,
Name: name
Email: email
}
}
package user
import "testing"
import "github.com/stretchr/testify/assert"
func TestUser(t *testing.T) {
var id int64 = 1
var name string = "Nakata"
var email string = "nakata@example.com"
user:= NewUser(id, name, email)
if user == nil {
t.Errorf("failed NewUser()")
}
assert.Equal(t, id, user.ID)
assert.Equal(t, name, user.Name)
assert.Equal(t, email, user.Email)
t.Logf("user: %p", user)
t.Logf("user.ID: %d", user.ID)
t.Logf("user.Name: %s", user.Name)
t.Logf("user.Email: %s", user.Email)
}
#テストの実行
下記のようにコマンドを実行すると、テストを実行できます。
$ go test //ログを出さない場合
$ go test -v //ログを出す場合
PASS
ok user 0.013s
#階層構造
t.Run
を使うことで、テストを階層構造にすることができます。
先ほどのサンプルを改良してみましょう。
package user
import "testing"
import "github.com/stretchr/testify/assert"
func TestUser(t *testing.T) {
t.Run("success NewUser()", func(t *testing.T){
var id int64 = 1
var name string = "Nakata"
var email string = "nakata@example.com"
user:= NewUser(id, name, email)
if user == nil {
t.Errorf("failed NewUser()")
}
assert.Equal(t, id, user.ID)
assert.Equal(t, name, user.Name)
assert.Equal(t, email, user.Email)
t.Logf("user: %p", user)
t.Logf("user.ID: %d", user.ID)
t.Logf("user.Name: %s", user.Name)
t.Logf("user.Email: %s", user.Email)
})
t.Run("success NewUser()", func(t *testing.T){
var id int64 = 2
var name string = "Suzuki"
var email string = "suzuki@example.com"
user:= NewUser(id, name, email)
if user == nil {
t.Errorf("failed NewUser()")
}
assert.Equal(t, id, user.ID)
assert.Equal(t, name, user.Name)
assert.Equal(t, email, user.Email)
t.Logf("user: %p", user)
t.Logf("user.ID: %d", user.ID)
t.Logf("user.Name: %s", user.Name)
t.Logf("user.Email: %s", user.Email)
})
}
テストを実行してみましょう。
$ go test //ログを出さない場合
$ go test -v //ログを出す場合
PASS
ok user 0.015s
#ベンチマーク
パフォーマンスの測定をしたい場合、BenchMarkXxx
と記載し、Xxxについてのパフォーマンスを測定します。
NewUser()
を測定してみましょう。
func BenchmarkUser(b *testing.B) {
var id int64 = 1
var name string = "Nakata"
var email string = "nakata@example.com"
b.ResetTimer()
for i:= 0; i < b.N; i++ {
user:= NewUser(id, name, email)
}
b.StopTimer()
if order == nil {
b.Errorf("failed NewUser()")
}
}
ベンチマークは、オプション-bench
をつけると実行できます。
$ go test -bench .
BenchmarkUser-4 30000000 46.6 ns/op
PASS
ok user 1.464s
さらに詳しい情報を知りたい場合は、-benchmem
も追加します。
$ go test -bench .
BenchmarkUser-4 30000000 45.5 ns/op 128 B/op 1 allocs/op
PASS
ok user 1.429s
BenchmarkUser-4の、各列の意味としては下記の感じです。
・関数の実行回数:多いほど良い
・1回の実行にかかった時間[ns/op]:少ないほど良い
・実行ごとに割り当てられたメモリのサイズ[B/op]:少ないほど良い
・1回の実行でメモリアロケーションが行われた回数[allocs/op]:少ないほど良い
#カバレッジ
テストをしていると、カバレッジも知りたくなります。
-cover
オプションをつけることで、テスト実行結果にカバレッジが表示されます。
$ go test -cover .
ok user 0.013s coverage: 100.0% of statements
#おわりに
Golangのテストに必要な物を調べて記載してみました。これでテストはできそうですね。
testify
については、よく使うものなどを追記していきます。