質問の背景
SQLにおけるビジネスロジックの手動検査(ストアドプロシージャ、関数、トリガーのレベルで)は、本番環境でのみ浮かび上がるエラーを引き起こします。長い間、SQLスクリプトのテストは非公式かつ標準化されていませんでした。しかし、CI/CD技術の発展は、SQLコードに対しても自動化されたテストを要求します。
問題
ほとんどの開発者はアプリケーションレベルのテストにしか限定していません。SQLプロシージャや関数自体の検証がないため、UDFロジックの変更やレポートの回帰など、どのテストパッケージにもカバーされない欠陥が生じます。
解決策
現代のチームのワークフローでは、SQLコード用のユニットテストおよび統合テストが直接組織されています。ユニットテストには、tSQLt(SQL Server)、utPLSQL(Oracle)、pgTAP(PostgreSQL)などのフレームワークが使用され、統合テストには、一時的なデータベースの立ち上げ、マイグレーションの適用、ビジネスシナリオの検証のための別の環境が使用されます。
pgTAPでのユニットテストの例:
-- 給与の計算を検証 SELECT plan(2); SELECT is( (SELECT calc_salary(1)), 1000, 'ユーザー1の給与は正しい' ); SELECT isnt( (SELECT calc_salary(2)), 0, 'ユーザー2の給与はゼロではない' ); SELECT finish();
CI/CD用の統合テストのコード:
psql -U user -d testdb < migrations.sql psql -U user -d testdb < test_data.sql psql -U user -d testdb -c "SELECT * FROM my_procedure_test();"
主な特徴:
大きなプロシージャがある場合、アプリケーションレベルの自動テストだけで済ませることはできますか? いいえ、UI/APIのテストは、SQLロジックの動作の正確性を保証しません(たとえば、ストアド関数内の不正確な条件やデータ更新時の問題など)。ユニットテストは、SQLコード自体のすべてのルート分岐をカバーする必要があります。
「手作業」でテストスクリプトを実行するだけで十分ですか—データベースの変更は少ないのですから? 十分ではありません。小規模なプロジェクトでも、スキーマやロジックの変更後にはバグが発生します。CIプロセスでのテストの自動化は、人間の要因を減少させ、回帰を防ぎます。
「重要な」プロシージャだけをテストし、その他はスキップできますか? 最善のアプローチは、可能な限り多くの関数をカバーすることです。特に将来的に異なるチームがコードを変更する場合、明白でない計算やエッジケースは、標準的でない分岐で最も頻繁に現れます。
割引計算のプロシージャを改訂する際、手作業で数ケースをテストし、主要なロジックの枝を見落としました。本番環境で顧客が誤った割引を受け取ることが始まり、問題解決には数日かかりました。
利点:
初期の時間節約。
欠点:
手動修正による損失、改訂やリファクタリングの際の不便さ。
pgTAPを使用して、すべての主要なUDFとプロシージャにユニットテストを開発し、CIを介して統合テストを各マージで実行しています。エラーや回帰はデプロイ前に発見されます。
利点:
機能の安定性、ビジネスロジックを迅速に改訂する能力、本番環境での最小限のバグ。
欠点:
テストベースの開始と保守に時間を投資する必要があります。