データベーステスト:UIのみをテストするエンジニアが見落としていること

Rui Li
データベーステスト:UIのみをテストするエンジニアが見落としていること カバー

多くの自動テストスイートはインターフェースをテストします。フォームの送信、ボタンのクリック、ページの読み込み、APIのレスポンス。これらのテストには価値があります。しかし、ある特定の重大な点で不完全です。アプリケーションが何を表示するかを検証するだけで、何を保存するかを検証していないのです。

データベーステストは、アプリケーションのデータ層が正しく動作することを検証します。つまり、適切なレコードが正しい値で作成・更新・削除されること、制約が適切に適用されること、トランザクションがアトミックに完了すること、そして操作後のデータベース状態がアプリケーションロジックの意図と一致することを確認します。

UIのみのテストが見落とすもの

UIが表示するものとデータベースが保存するものの間のギャップこそ、最もコストの高いバグが潜む場所です。

フォームの送信で成功確認が表示されても、データベースには不正なデータが書き込まれている場合があります。UIテストはパスします。データベースのレコードは誤っています。フォームを送信したユーザーは、後で戻ってデータが消えているか破損しているのを発見するまで、データが正しく保存されなかったことに気づきません。

カスケード効果も同様に見落とされやすい問題です。対象レコードを正しく更新する操作が、関連レコードを誤って変更するカスケードを引き起こす場合があります。UIにはプライマリの変更のみが表示されます。二次的な影響は、下流の機能が破損した状態を露呈するまで不可視のままです。

ソフトデリートは、微妙な障害の根強い原因です。レコードを物理削除せず削除フラグを立てるアプリケーションは、ソフト削除されたレコードがクエリに表示されないこと、カスケードロジックが正しく処理されること、復元操作が完全なレコード状態を回復することを検証する必要があります。これらはいずれもUIレイヤーからは確認できません。

制約テストのギャップ

データベース制約(ユニークインデックス、外部キー関係、チェック制約、NOT NULL要件)は、ストレージ層でデータベースが保証するデータ整合性の仕組みです。アプリケーションコードが制約違反を正しく処理するかどうかのテストは、制約そのものが正しく定義されているかのテストとは別物です。

どちらもテストする必要があります。ユニーク制約違反を握りつぶしてユーザーに通知しないアプリケーションは、エラーなしに重複レコードを受け付けているように見えます。スキーマから外部キー制約が欠落していると、下流のクエリを壊す孤立レコードが生まれます。

AIテストワークフローへのデータベースアサーションの統合

TestSpriteのテストフレームワークは、エンドツーエンドのテストフローの一部としてデータベース状態の検証をサポートしています。データベースへの書き込みを伴うテストアクションの後、テストはUIが期待する確認を表示するかどうかだけでなく、正しい値でデータベースレコードが存在するかどうかをアサートします。

このアプローチにより、UIの検証はパスしながらデータ状態をサイレントに破壊するクラスの障害を検出できます。これらはしばしば本番環境で最も診断が困難な障害です。なぜなら、症状(データの誤り)が原因(サイレントに失敗した書き込み、または誤った値の書き込み)と時間的・文脈的に乖離しているからです。

スキーママイグレーションテスト

データベーススキーマのマイグレーションは、アプリケーションレベルのテストとは別に、独自のテストカバレッジが必要です。少量のデータセットで開発データベース上では正常に実行されるマイグレーションも、数年分の蓄積データ、非推奨フォーマットのレガシーレコード、開発環境では現れなかったエッジケースを抱える本番データベースに対しては失敗したり、誤った結果を生む場合があります。

匿名化または合成した本番代表データに対してマイグレーションをテストしてから本番に適用することは、最も価値の高いプラクティスの一つですが、手間がかかるという理由でほとんどのチームが省略しています。これによって防げるインシデントは、データ損失、レコードの破損、時間的プレッシャーの中でロールバックを要する展開失敗など、影響が特に甚大なものばかりです。