MySQLやRabbitMQ、Redisなどに接続する処理があるサービスのテストを書こうとしたらハマった。
golang1.4から
func TestMain(m *testing.M)
という関数が定義されていればこれがまず実行されて、ここに初期化処理や終了時の処理を書けば良いということだったので、mainパッケージにmain_test.goのようなファイルを作り、envファイルのロードや、DBの接続を行う処理を書いた。
(参考:http://golang-jp.org/pkg/testing/ )
package main
import (
"testing"
"github.com/my_account/my_worker/cmd"
"github.com/my_account/my_worker/models"
"os"
)
//Check variables @ config/env/test.env
func TestMain(m *testing.M) {
before()
code := m.Run()
after()
os.Exit(code)
}
func before(){
cmd.InitConfig() //環境変数のロード
models.InitDBConnection() //DB接続処理
}
func after(){
}
初期化処理ができたので、テスト書いていくかーと思い
models/aaa_test.goみたいなファイルを作り、テストを書いてみたが、どうもDBの接続に失敗しているらしく読み込んだはずの環境変数も取得できない。
package models
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestIsWhiteListed(t *testing.T) {
b := IsWhiteListed(123456, 34)
assert.Equal(t, b, true, "they should be equal")
}
そもそもmain_test.goでの初期化処理が失敗してるのでは?と思いmain_test.goのbefore()関数の後で環境変数やパッケージのグローバル変数をチェックすると正しく処理できていた。
その後小一時間ほど悩んで試行錯誤している時に
m.Run()
を消してテストを実行したところ、models/aaa_test.goのテストが走ったので、これはもしかして・・と思い
models/init_test.goみたいなファイルを作り、ここにも
func TestMain(m *testing.M)
を定義して、初期化処理を行ったら予想通りの動きをしくれた。
どうやら初期化処理を行いたい場合は、パッケージ毎に
func TestMain(m *testing.M)
が必要らしい。
あと、環境変数のロードはgodotenv( https://github.com/joho/godotenv )を使っていたんだけど、どうやらテストが実行されるパッケージごとにカレントディレクトリが変わるらしく、repositoryのルートに.envを置いている場合は
godotenv.Load("../.env")
のようにしてロードしないとダメみたいです。