go-sqlmockのTips
まとめ
- 動作確認したのは
v1.3.3
- database/sqlのテストはgo-sqlmockを使うと比較的楽に行える
- クエリのmatcherには正規表現が使える
- Rowsからエラーを受け取りたい場合は、エラーが発生する行のデータを作る必要がある
- 不要なエラーのチェックだけならsqlmock.ExpectationsWereMetは呼び出さなくてもよい
まえがき
golangでSQLを使うコードを書く場合、database/sql
を使うことになるが、golangの標準ライブラリだけでこれのテストを書くことは非常に辛い。
おそらくDBを実際に用意してテストするしか無いが、様々なエラーケースのテストが必要な場合それだけではテストしきれない。
この記事ではDATADOG/go-sqlmockを使ってテストした際のTipsをまとめておく。
はじめに
基礎的な部分はREADME.mdやexamples、godocを読めば事足りるが、以下に忘れがちな内容を記載する。
Query matcher
クエリが実行されたかどうかをチェックするにあたって、呼び出された回数だけをチェックしたいケースが有る。 このような場合は、正規表現を使うことで対処できる。
mock.ExpectQuery(".*").WillReturnRows(rows)
雑だがgomockのAny()相当のことがしたい場合はこれで実現可能である。 また、QueryMatcher自体を自分でカスタマイズすることも可能だがこちらは試していない。
refs: https://godoc.org/github.com/DATA-DOG/go-sqlmock#QueryMatcher
Rowsからエラーを受け取る
クエリの結果エラーを受け取りたい場合、 ExpectedQuery.WillReturnRows
にエラーを含む sqlmock.Rows
を登録することになるが、このとき以下のようにしてしまうとエラーが発生せずにハマることになる。
sqlmock.NewRows([]string{"ID"}).RowError(0, commonErr)
パッと見は最初の行でエラーが出そうであるが、これではエラーは出ない。 多分この辺のせい。 以下のようにエラーが発生する行数になるまでAddRowを実行する必要がある。
sqlmock.NewRows([]string{"ID"}).AddRow(1).RowError(0, commonErr)
不要な呼び出しのチェック
READMEのサンプルではmock.ExpectationsWereMet
を実行してmockが呼び出されているか検証しているが、
SQLが実行されなかったことを保証するだけであれば
このメソッドを呼び出さずとも良い。
例えばvalidationの結果、SQLが実行されないようなケースのテストでそのようなテストが必要になる。
ExpectXXX系のメソッドが呼ばれなかった場合に db.QueryContext
のようなメソッドを実行すると、sqlmockがエラーを返すためそれを検証すれば良い。