PostgreSQLをバックエンドとしたアプリのテスト方法を求めて
バックエンドにPostgreSQLを使った(Web)アプリのより良い単体テスト方法を探っている。
アプリはGo製、ORMにはxormを用いてる。
もっとも原始的に、ローカルにPostgreSQLをインストールしてpg_ctlでテスト毎、もしくはpackage毎にDBを作ってしまうことを考えた。
結果 koron-go/pgctl が生まれた。
これはテスト毎にDBインスタンスが立つのでテストとしては理想的だったが、いかんせんインスタンスの起動が遅いので気軽にユニットテストを実行する気になれなかった。
テスト用のPostgreSQLインスタンスを起動しっぱなしにし、各テストはデータが被ったり残ったりしないように棲み分けることを考えた。
テスト間に薄い依存ができてしまったのと、テストデータの掃除に失敗すると復帰が面倒なのと、さらにはパッケージを超えて並列にテストを実行すると問題が起こりやすい。
使えなくはない(実際に一部では使ってる)があまり良くもない。
ユニットテストではPostgreSQLの代わりにSQLite3を使ってみた。どうせORMをかぶせてるんだからORMがサポートしているDBならなんでも良いやろという発想。
多くの機能はこの方法で問題なかったが、一部のPostgreSQL固有の機能(jsonb, postgis等々)に依存した機能は当然NGだった。
またconstaintに引っかかるような半正常系についても、PostgreSQLドライバー固有のエラーを解釈しており、xormでは処理されてないこともありテストができなかった。SQLite3はどうもconstraintに引っかかったフィールド名などを取るのが難しそう。
ただし速度やテスト間の独立性など満足できた点は多い。現実的にはこのあたりが落としどころだと考えている。
benbjohnson/postliteを知り、こいつでテスト用のPostgreSQLを置き換えられないかと考えた。
実際にやってみて無理だなとなった。postliteはあくまでもSQLite3にPostgreSQLプロトコルを喋らせてリモートアクセスできるようにしようというものだった。PostgreSQLを置き換えられるものではない。
postliteを調べる過程で jackc/pgmock を知った。PostgreSQLのプロトコルレベルでmockingするテストに使えそう。
発行されるSQL文の文字レベルでテストを記述する必要があるのと、本来興味がないPostgreSQLプロトコルレベルの知識を必要とするのでtoo much感が強い。
まぁ1回やってしまえばかなりの部分を使いまわしできるとは思うが、面倒さに見合うかイマイチわからない。ただテスト用にfixtureを管理しなくて良いという魅力(?)もある。いややっぱダメかな。
本来は xorm のレベルでモックできれば一番良い。
教えてもらったやつ。
DATA-DOG/go-txdb - 実物のDBを使いつつ、各テストのコネクションをトランザクションで独立に保つ仕組みっぽい。
テスト間の薄い依存を解決する手段としては納得。ただPostgreSQLのインスタンスと、スキーマのセットアップは要ることになる。
残念ながら僕の用途ではあんま導入するメリットがなさそう。