布団の中にいたい

Elasticsearchいじったり、Androidアプリ書いたり。最近は数学の勉強が楽しくなってきました。

goでDBのテストを書くときに、go-sqlmockを使ってみた

goでDB周りのテストをするときに、毎度テスト用のDBにデータを流し込んで終わったら削除する、みたいなことをしていたのだけれど、若干面倒だなーと思い始めたのでgo-sqlmockを使ってみました。

go-sqlmockはgo用のmockライブラリです。

github.com

公式のサンプルではそのままdatabase/sqlを使っていますが、普通にgormでも使えて以下のような感じで使えます。


func main()  {
    db, mock, err := sqlmock.New()
    if err != nil {
        log.Fatal(err)
    }

    gdb, err := gorm.Open("sqlmock", db)
    if err != nil {
        log.Fatal(err)
    }
        
       // 後は、gorm.Openの返り値を使って色々やる
}

gorm.Openの引数にsqlmockを使っていますが、内部でそれに対する値があるわけではないのでwarningが出ますが、特に問題なく使えます。

具体的な使い方ですが、リポジトリのexampleがあるのでそちらを参考にするといいと思います。

加えて、微妙にハマった点ですが、go-sqlmockではクエリを正規表現でマッチングしている都合上、テストコードに正規表現混じりのSQLを書くか各メタ文字をエスケープする必要があります。そのせいでテストがなかなか通らなかったりしたのですが、regexpのQuoteMetaを使うと、一括でメタ文字をエスケープしてくれるので大変便利です。

regexp - The Go Programming Language

QuoteMetaを使うとだいたい以下のような形で書き換えられます。

// regexp.QuoteMetaを使わないもの
mock.ExpectQuery("^SELECT (.+) FROM samples$")


// regexp.QuoteMetaを使ったもの
mock.ExpectQuery(regexp.QuoteMeta("SELECT * FROM samples"))

感想

goのDBのテストにgo-sqlmockを使ってみました。テスト用のDBから読み出すことに比べて事前に何のデータは入っているかを意識しなくていいので心持ち的にはだいぶ楽になったように思います。加えて、regexp.QuoteMetaを使えば細かいこと意識しなくてもよくなるのでこちらも楽になりました。ただ、細かい速度比較はしていないので、大規模なアプリケーションで使う場合は確認したほうがよいかと思います。