はじめに
データベースを使うテストにはいくつかやり方があります。
- モックを使う Goだとgo-sqlmockとか
- テストの時は軽量DBを使う sqlite3とか
- 実際のDBに接続する。dockerとか
ちょっと複雑なクエリを試したいときとかにはやっぱり実際のDBを使いたいです。
実際のDBに接続するテスト
実際にDBに接続するテストだといくつかネックになるポイントがあります。
- DBの初期化(DDLなど
- テスト実行後のテストデータの後処理(消す
Goにはテストの前処理や後処理を書く仕組みがあります。
https://golang.org/pkg/testing/#hdr-Main
なお、同じパッケージ内に複数のTestMainを記述することはできないので注意が必要です。
package foo
import (
"testing"
)
func TestMain(m *testing.M) {
// 前処理 Open connectionとか
// DDLを流すとか
m.Run()
// 後処理 Close connectionとか
}
func TestFoo(t *testing.T) {
// ...
}
そして各テストメソッドの中でもデータを消す必要があります。
func TestFoo(t *testing.T) {
// ...
deleteTestData()
}
ちなみにデータを消す時はDELETE
よりもTRUNCATE
の方が速いです。
大量のテーブルのデータをまとめて消したりする際はDROP
するかもしれませんが、重たいのでオススメしません。
各テストメソッドごとにDROP
するとテストメソッドが増えた際にどんどんテストとの実行時間が長くなっていきます。
ここで一つ思いつくでしょう。
データ消すのめんどくさいからテスト中のトランザクションをロールバックすればよくね?
go-txdb
go-txdb
このライブラリを使うとDBコネクションをOpenしてからCloseするまでの間のトランザクションを全てロールバックしてくれます。
使い方は簡単でREADMEにあるとおりです
// https://github.com/DATA-DOG/go-txdb/blob/master/README.md
package main
import (
"database/sql"
"log"
"github.com/DATA-DOG/go-txdb"
_ "github.com/go-sql-driver/mysql"
)
func init() {
// we register an sql driver named "txdb"
txdb.Register("txdb", "mysql", "root@/txdb_test")
}
func main() {
// dsn serves as an unique identifier for connection pool
db, err := sql.Open("txdb", "identifier")
if err != nil {
log.Fatal(err)
}
defer db.Close()
if _, err := db.Exec(`INSERT INTO users(username) VALUES("gopher")`); err != nil {
log.Fatal(err)
}
}
ちなみにgo-txdbを使う場合は各テストメソッドの中でコネクションをOpenしてdeferでCloseすればOKです。
サブテストの中でCloseするのもいいかもしれません。
全てテストメソッド内で完結させられるので同じパッケージ内であっても前処理や後処理を書き分けたいときにも使えると思います。
手軽に始められるのでオススメですが、テストが終わるとデータが全部消えてしまうのでテストコードのデバッグは結構大変です。