Queryのユニットテスト
Queryのユニットテストについて考える。
SQLに代表されるQueryの場合、入力よりも状態に大きく依存するのでExample Based Testingが書きづらく、メンテナンスも大変だ。
現状の調査
実際に書かれているテスト
redmine
Fixtureを用意し、固定のクエリを実行して、その結果を固定の値でAssertionする。典型的なExample-based testing。
ノウハウ
xUnitにはDatabaseを伴うテストのテクニックにはいくつか言及があるが、クエリのテストに関しては特に記述なし。
ATDD by Exampleでは、Query Tablesが紹介されていて、これは表形式で期待する結果セットを書く。
ツール
定番があるとは言い難い。
DBUnit
古くから存在するSQLレベルでのユニットテストツール
SQLServer専用(正確にはT-SQL専用)
PLSQLでゴリッとテストコード書く
課題
DBUnitのようなツールを使ったユニットテストでは以下の課題が残存する。
Fixtureの質が、テストの質に直結する
AssertionがExampleベース(実際にSELECTした結果と同じデータであることを検証するためのデータセットを予め用意しておく)だと、そのメンテナンスが大変すぎる。
本来SELECTされるべき行が、結果セットに存在しないことをテストしていない。
WIP:ソリューション
上記課題を解決するため、次のようなQuery用のUnit Testツールが必要だと考える。
FixtureはテストのSetupとして投入しても、事前に構築済みのDatabaseを使ってもよいが、Queryのバリエーションに十分に対応できるデータが用意されている(特にSELECTされてないデータパターンも十分に含まれている)。
Assertionは、QueryがWHERE句で絞り込む前の全件データを対象とし、Verify用のDSLで定義した条件を使って、SUTのQuery結果と比較して、対象のみが過不足無く抽出できているかを検証する。
https://gyazo.com/ca2a1a4c2d6a6bad1359855de724e4e6
単純なSELECTでの例
code:sql
SELECT *
FROM emp
WHERE salary >= 10000000
このケースにおいて、クエリの仕様は、
年収1千万円以上の従業員を抽出する
となる。
したがって、クエリの実行結果に対して、
年収1千万円以上の人が漏れなく抽出されている。
年収1千万円未満の従業員は抽出されていない。
が検証されていて欲しい。
code: verify dsl
target: emp
filters:
- salary >= 10000000
table:emp
id name salary
1 Alice 8500000
2 Bob 12000000
3 Carol 6000000
というデータセットに対して前述のクエリは、
table:query_result
id name salary
2 Bob 12000000
だけを返してくるが、Verifyの工程では、
(1, Alice, 8500000)がfilters: salary >= 10000000を満たすかチェック。falseであるので、query_resultに含まれないことをverify
(2, Bob, 12000000)がfilters: salary >= 10000000を満たすかチェック。trueであるので、query_resultに含まれることをverify
(3, Carol, 6000000)がfilters: salary >= 10000000を満たすかチェック。falseであるので、query_resultに含まれないことをverify
のような検証を行うイメージ。