データ整合性テストの進め方|不整合を防ぐ観点

テストにお悩みの方へ

😢開発リソースが足りない...
😢リリース直前だけどテストの余裕がない
😢開発コストを抑えたい

上記のようなお悩みに対して、テスト代行サービスを運営しています。まずは無料お問い合わせください。

「在庫は0のはずなのに注文が通ってしまった」「売上を締めたら、合計金額が明細の合算と1円ずれていた」。こうしたデータの食い違いは、画面の見た目には現れにくく、発覚したときには顧客対応や返金、再集計まで巻き込む大きな事故に化けます。機能テストは通っているのに、データだけが静かに壊れていく。この見えにくさこそが、データの整合性という領域の難しさです。

本記事では、稼働中システムのデータが「正しい状態を保っているか」を検証するデータ整合性テストの観点と進め方を、受託開発の現場目線で整理します。データベースの制約から、トランザクション・状態遷移・バッチ・外部連携まで、不整合が生まれる典型パターンを押さえ、観点漏れなくテストを組み立てられるようにするのが狙いです。テスト設計をエンジニアに兼任させている体制でも、確認すべき勘所を共有できる内容にしています。

目次

データ整合性テストとは何か|3つの整合性の層

データ整合性とは、データが「ある時点で満たすべき正しさのルール」を破っていない状態を指します。ひとくちに整合性と言っても、守るべきルールには階層があります。まずはこの層を分けて捉えることが、観点漏れを防ぐ第一歩です。

整合性は、大きく次の3層に分けて考えると整理しやすくなります。技術的に低いレイヤーから、業務に近いレイヤーへと積み上がっていくイメージです。

整合性の種類守る対象崩れたときの例
第1層ドメイン制約・実体整合性型・NOT NULL・一意キー・CHECK制約数量にマイナス値、主キー重複
第2層参照整合性外部キー(親子関係)注文明細に存在しない商品IDが残る
第3層業務ルール上の整合性アプリが保証する業務不変条件在庫数と引当済み数量の合計が合わない

第1層と第2層は、データベースの制約機能である程度守れます。一方で最も事故が起きやすいのは第3層の業務ルール上の整合性です。「在庫と注文の関係」「残高と取引明細の関係」といった、複数テーブルにまたがる不変条件はDBの制約だけでは表現しきれず、アプリケーションのロジックに委ねられているからです。

整合性の検証で最も手厚く見るべきは、DB制約で守れない「業務ルール上の整合性」です。ここが崩れると、個々の画面やAPIは正常に動いているように見えるのに、データ全体としては矛盾した状態に陥ります。

  • 実体整合性: 各行が一意に識別でき、必須項目が欠けていないこと
  • 参照整合性: 親レコードのないデータ(孤児レコード)が生まれないこと
  • 業務ルール整合性: 業務上「あってはならない組み合わせ」が存在しないこと

もうひとつ意識したいのが、マスタデータとトランザクションデータの関係です。商品マスタや顧客マスタのような「基準となるデータ」と、注文や入出庫のような「日々発生するデータ」は、参照する側とされる側の関係にあります。マスタが変更・削除されたとき、過去のトランザクションが参照していた情報が失われると、履歴の再現ができなくなります。

たとえば、販売済み商品の単価をマスタ上で改定したとき、過去の注文金額まで変わってしまう設計では、売上履歴の整合性が崩れます。マスタの変更を過去データに波及させない仕組み(注文時点の値をトランザクション側にコピーして保持する等)が正しく働くかは、整合性の観点として見逃せません。

なお、本記事が対象とするのは稼働中のシステムでデータが正しく保たれ続けるかの検証です。移行時に旧システムのデータを正しく移し替えられたかを確認する観点は主題が異なるため、データ移行テストの進め方と検証設計で別途整理しています。あわせて確認すると、移行と運用の両面をカバーできます。

なぜデータの不整合は見つけにくく、事故が大きくなるのか

データの不整合が厄介なのは、発生と発覚のあいだに大きな時間差があるからです。バグが混入した瞬間には誰も気づかず、月次の締め処理や監査、あるいは顧客からの問い合わせで初めて表面化します。その頃には、壊れたデータを前提にした処理がさらにデータを積み上げており、被害が拡大しています。

不整合が見つけにくい理由を、現場で起きる典型として挙げます。

  • 画面上は正常に見える: 一覧や詳細画面は個別のレコードを表示するだけで、レコード間の矛盾は表示されない
  • 正常系テストでは踏まない: 手順通りに操作する限り整合性は保たれ、異常な割り込みやタイミングでしか壊れない
  • 再現条件が同時実行やタイミングに依存する: 単体では再現せず、負荷や競合が重なったときだけ発生する
  • 統計的に埋もれる: 数十万件のうち数件の不整合は、目視やサンプル確認では発見できない

不整合は「起きた瞬間」ではなく「使おうとした瞬間」に牙をむくため、検知が遅れるほど復旧コストが跳ね上がります。発覚が遅れると、原因調査に加えて過去データの遡及修正が必要になり、影響範囲の特定だけで数日を要することも珍しくありません。

だからこそ、機能が仕様通り動くかという観点とは別に、データが矛盾していないかを独立した観点として検証する必要があります。リリース直前にテストが間に合わず品質を妥協しがちな現場ほど、この観点が抜け落ちやすい点に注意が必要です。上長やクライアントに品質リスクを説明する際も、「データ不整合は発覚が遅く復旧費用が大きい」という費用対効果の文脈で語ると納得を得やすくなります。

具体的な事故の流れをイメージしてみます。ある通販システムで、決済処理中に例外が起きて注文レコードだけが中途半端に作られたとします。画面上はエラーになるため、利用者も開発者もその場では問題に気づきません。しかし夜間の在庫連携バッチがその不完全な注文を拾い、実在しない出荷指示を外部倉庫に送ってしまう、という二次被害に発展します。最初の小さな不整合が、時間差で複数のシステムを巻き込むわけです。

このように、不整合は単独では収まらず連鎖して被害を広げる性質があります。ひとつのテーブルの矛盾が、それを入力とする別処理の前提を崩し、さらに下流へと波及します。テスト設計では、不整合が「どこで生まれ」「どの処理に波及するか」という影響の連鎖まで想像しておくと、優先的に守るべき箇所が見えてきます。

トランザクションの整合性を検証する観点

複数の更新をひとまとまりとして扱うのがトランザクションです。銀行振込で「口座Aから引く」と「口座Bに足す」が両方成功するか、両方失敗するかのどちらかでなければならない、という考え方が典型例です。ここでの整合性を支える基本概念が、原子性・一貫性・独立性・永続性の4つの性質(ACID特性)です。

ACID特性の考え方は、各データベース製品の公式ドキュメントでも定義されています。用語の正確な理解には、PostgreSQL日本語ドキュメントなどの一次情報を参照することをおすすめします。

性質意味テストで確認したいこと
原子性(A)全部成功か全部失敗か途中で失敗したとき、部分的な更新が残らないか
一貫性(C)制約を満たした状態を保つ処理前後で不変条件が保たれているか
独立性(I)同時実行が互いに干渉しない並行更新で片方の結果が消えないか
永続性(D)確定した結果は失われない障害後もコミット済みデータが残るか

トランザクション周りで特に検証すべき観点を、具体的なテスト手順として挙げます。

  • ロールバックの確認: 処理の途中で意図的にエラー(在庫不足・通信断・例外)を発生させ、開始前の状態に完全に戻るかを検証する
  • 原子性の境界: 「どこまでを1トランザクションにするか」の設計を確認し、複数トランザクションに分割された箇所で中間状態が残らないかを見る
  • 同時実行・競合: 同じレコードを複数の処理が同時に更新したとき、後勝ち・先勝ち・エラーのいずれの仕様なのかを明確にし、その通りに動くか検証する
  • デッドロック: 2つの処理が互いのロックを待ち合う状況を作り、タイムアウトやリトライで安全に解消されるかを確認する
  • 排他制御: 悲観ロックと楽観ロックのどちらを採用しているかを把握し、更新競合時に「更新が握りつぶされない」ことを確かめる

同時実行のバグは、2つのブラウザやAPIクライアントで同一データをほぼ同時に更新する「競合再現テスト」で初めて表面化します。1人で順番に操作するテストでは決して踏めないため、意図的に競合状態を作り出す設計が欠かせません。

とりわけ在庫引当や残高更新のように「読み取った値をもとに計算して書き戻す」処理は、二重更新(ロストアップデート)が起きやすい代表例です。読み取りから書き込みまでのあいだに別の処理が割り込むと、片方の更新が上書きで消える恐れがあります。楽観ロックのバージョン番号や、在庫数に対する条件付き更新(在庫が足りる場合のみ減算するSQL)で防いでいるかを、テストで具体的に突きます。

また、同時実行の振る舞いはトランザクション分離レベルの設定にも左右されます。分離レベルによって、ほかのトランザクションが未確定の変更を読んでしまう(ダーティリード)、同じ問い合わせで結果が変わる(ファジーリード)、といった現象の起こりやすさが変わります。使用している分離レベルを開発チームに確認したうえで、その設定で許容される現象が業務上問題ないかを検証するのが実務的です。

  • ダーティリード: 未コミットの変更が他の処理から見えてしまう
  • 反復不能読み取り: 同一トランザクション内で同じ行を読んでも値が変わる
  • ファントムリード: 検索条件に合致する行数が途中で増減する

これらの現象は、分離レベルを上げれば防げますが、その分ロック競合が増えて性能に影響します。整合性と性能はトレードオフの関係にあるため、「どこまでの厳密さが業務上必要か」を仕様として明確にし、その前提でテストの合否基準を決めることが大切です。分離レベルの厳密な定義は前述のデータベース公式ドキュメントに整理されています。

状態遷移とデータの一貫性を確認する観点

注文ステータス(受付→与信→出荷→完了)や、在庫の状態(引当→確保→出荷済み)のように、データは決められた順序で状態を変えていきます。この遷移のルールが崩れると、「キャンセル済みなのに出荷される」「未払いなのに完了扱いになる」といった、業務上あってはならない不整合が生まれます。

状態遷移を検証する際は、正しい遷移だけでなく許されない遷移が拒否されるかまで確認するのが要点です。Copelandは『はじめて学ぶソフトウェアのテスト技法』で、状態遷移図は一見して理解しやすいものの、抜け漏れのない体系的な分析には状態遷移表のほうが使いやすいと指摘しています。すべての状態とイベントの組み合わせを表として洗い出すことで、想定していなかった遷移の穴が見えてきます。

確認区分観点具体例
正常遷移定義された順序で進むか受付→与信OK→出荷が正しく進む
異常遷移の拒否飛び越し・逆行を弾くか受付から直接「完了」に飛べない
多重遷移同じ操作の二度押しを防ぐか出荷確定を2回押しても在庫は1回だけ減る
関連データの同期状態変更で関連データも整合するかキャンセル時に引当在庫が戻る

特に見落としがちなのが、状態変更に連動して更新されるべき関連データです。注文をキャンセルしたのに引当在庫が戻らなければ、在庫だけが目減りしていきます。状態を持つデータは、その状態と紐づく数量・金額・フラグが常に足並みをそろっているかをセットで検証します。

もうひとつ注意したいのが、途中で止まった遷移の後始末です。ネットワーク断やブラウザの強制終了で、状態遷移が中途半端に終わることは現実に起こります。「与信は取ったが注文確定に至らなかった」といった宙ぶらりんの状態が残ると、在庫だけ引き当てられたまま解放されない、といった不整合につながります。一定時間で自動的にキャンセル扱いにする、あるいは定期的に宙ぶらりんの注文を検出して解消する仕組みが正しく働くかも、あわせて確認しておきたい観点です。

状態遷移テストの技法そのものについては、状態遷移図を活用したテストアプローチで図と表の使い分けを含めて解説しています。データ整合性の観点と組み合わせると、遷移の網羅性を高められます。

  • 各状態から出る「正しい遷移」を最低1回ずつ通す
  • 各状態への「あり得ない遷移」を試み、拒否されることを確認する
  • 二度押し・リロード・戻る操作など、UI起因の多重遷移を再現する
  • 状態変更後に関連テーブルの数量・金額を検証SQLで突き合わせる

集計・バッチ処理の整合性を検証する観点

日次の締め処理や月次の集計バッチは、大量のデータをまとめて処理するぶん、不整合が起きると影響が広範囲に及びます。しかも夜間に自動実行されることが多く、異常があっても翌朝まで気づけません。ここでは「明細と合計が一致するか」という突合の観点が中心になります。

バッチ処理で押さえるべき観点を整理します。

観点リスク検証方法
明細と集計の一致合計金額が明細合算とずれる集計結果と明細のSUMをSQLで突合
二重実行同じバッチが2回走り二重計上同一バッチを連続実行し件数・金額を確認
再実行の安全性途中失敗後の再実行で重複や欠落中断→再実行で最終結果が同一か検証
対象データの境界締め時刻をまたぐデータの取りこぼし締め時刻の前後1秒のデータで確認
大量データ件数増でタイムアウト・途中断本番相当件数で完走するか検証

バッチ処理の整合性検証では「同じ処理を2回流しても結果が変わらない」という再実行可能性(冪等性)が最重要のチェックポイントです。障害でバッチが途中停止し、オペレーターが安全のためもう一度流す、という運用は現実に頻発します。そのとき二重計上や重複登録が起きないよう設計されているかを、テストで必ず突きます。

特に締め処理では、締め時刻の境界が事故の温床です。「23時59分59秒の取引はどちらの締めに含まれるのか」といった境界の仕様を明確にし、その前後のデータで狙い撃ちのテストを行います。境界付近の値を集中的に検証する考え方は、境界値分析のやり方とテストケースの作り方の手法がそのまま応用できます。

再実行の検証では、途中で強制的に処理を止めてから再度実行し、最終的なデータが正常に完走したときと一致するかを確認します。中間コミットの単位、処理済みフラグの持ち方、リカバリ手順の3点をあわせて点検すると、再実行時の抜けを防ぎやすくなります。

外部連携・非同期処理での整合性を保つ観点

決済ゲートウェイや在庫管理、物流システムなど、外部システムとの連携が絡むと整合性の難易度は一段上がります。自システムのトランザクションでは外部の状態まで巻き込めないため、「自分側は成功したのに相手側は失敗した」という片側だけの成立が起こり得るからです。

外部連携で典型的に起きる不整合を挙げます。

  • 決済は成立したのに注文が未確定: 決済APIの応答前に通信が切れ、二重課金や課金漏れが疑われる状態になる
  • 在庫連携のタイムラグ: 自システムと外部倉庫の在庫数が一時的にずれ、売り越しが発生する
  • 非同期メッセージの重複・欠落: キュー経由の連携でメッセージが二重配信、または消失する
  • 順序の逆転: 「確定」より先に「キャンセル」が届くなど、イベントの到着順が入れ替わる

こうした連携では、すべてを瞬時に一致させるのではなく、最終的に整合すればよいという結果整合性の設計が採られることが多くあります。この場合のテストでは、「一時的にずれている状態」と「最終的に一致すべき状態」を区別し、一定時間後や再送後に必ず整合するかを検証します。

ここで大切なのは、「一時的なずれ」を不具合と早合点しないことです。結果整合性を前提とした設計では、ある瞬間だけ見ればデータが食い違っているのが正常な振る舞いです。テスト担当者がその設計思想を理解していないと、正しい挙動をバグとして報告したり、逆に収束すべきタイミングを過ぎてもずれたままの本物の不整合を見逃したりします。「いつまでに」「どの状態に」収束すべきかという許容時間と最終状態を、テストの合否基準として仕様に落とし込んでおくことが欠かせません。

観点確認すること補足
冪等性同じ通知を複数回受けても二重処理しないか決済コールバックの再送を想定
タイムアウト時の扱い応答不明時に照会・リトライで収束するか「不明」を「失敗」と即断しない
補償処理片側失敗時に取り消し処理が走るか決済取消・在庫戻しが確実か
到着順の逆転順序が入れ替わっても矛盾しないかタイムスタンプや状態で判定

外部連携のテストでは「応答が返ってこない(タイムアウト)」状態を意図的に作り、システムが不明な状態から正しく収束するかを必ず確認します。成功と失敗の2択でテストを組みがちですが、実務で最も事故るのは「結果が分からない」第3の状態です。

決済まわりの整合性は金銭事故に直結するため、観点の網羅が特に重要です。決済に固有の確認項目は決済システムのテスト観点と事故る領域にまとめており、二重課金や金額端数の扱いなど、データ整合性と密接に関わる論点を補完できます。

データ整合性テストの進め方|準備から突合まで

ここまでの観点を、実際のテスト作業としてどう進めるかを整理します。この検証の基本動作は、実行前後のデータを比較し、あるべき状態との差分を突き合わせることです。以下の手順を軸に組み立てます。

  1. テストデータの準備: 整合性が崩れやすい境界のデータ(在庫0付近、上限額付近、状態遷移の端)を意図的に用意する
  2. 実行前スナップショット: 対象テーブルの件数・合計・キー項目を検証SQLで記録する
  3. 操作・処理の実行: 検証したいトランザクションやバッチ、連携を実行する
  4. 実行後の突合: 実行後のデータを再取得し、期待する差分と一致するかを比較する
  5. 検証SQLによる不変条件チェック: 「あってはならない状態」を検出するSQLを流し、0件であることを確認する

この「あってはならない状態を検出するSQL」を、いくつか具体的に持っておくと現場で役立ちます。たとえば在庫管理なら、商品ごとに「物理在庫数」と「引当済み数量の合計」を集計し、引当が物理在庫を超えている商品を抽出する問い合わせを用意します。受注管理なら、注文ヘッダの合計金額と、明細の金額×数量の合算が一致しない注文を洗い出す問い合わせが有効です。

これらの検証SQLは、一度作れば繰り返し使える資産になります。テスト実行のたびに流すのはもちろん、本番環境でも定期的に実行して結果を監視すれば、運用中に忍び込んだ不整合を早期に発見する仕組みとして機能します。テストと運用監視で同じ検証SQLを共有する発想を持つと、投資対効果が高まります。

データ整合性テストの成否は、「あってはならない状態を検出する検証SQL」をどれだけ用意できるかにかかっています。たとえば「引当在庫の合計が物理在庫を超える行」「親のない注文明細」「明細合計と受注金額が一致しない注文」を抽出するSQLを整備し、テストのたびに実行します。これらが1件でもヒットすれば不整合の証跡です。

検証観点の抜け漏れを防ぐため、チェックリスト形式で最終確認するのが有効です。

分類チェック項目確認
制約一意キー・NOT NULL・CHECK制約が効いているか該当
参照整合性孤児レコードが生まれないか該当
トランザクション失敗時にロールバックで完全復元されるか該当
同時実行競合更新でロストアップデートが起きないか該当
状態遷移不正な遷移が拒否され関連データも同期するか該当
バッチ二重実行・再実行で重複計上が起きないか該当
外部連携タイムアウト・重複通知で二重処理しないか該当
突合明細と集計、在庫と引当が一致するか該当

大量データや境界データを扱うため、テストデータの作り込みは整合性テストの品質を左右します。本番相当のボリュームや、個人情報のマスキングを含む準備の実務は、テストデータの作り方とマスキングの実務で具体的に解説しています。準備の段取りを固めることで、検証の精度と再現性が高まります。

進め方をチームに定着させる際は、いきなり全観点を網羅しようとせず、過去に事故が起きた領域と、金銭・在庫が絡む領域から優先して着手すると、少人数の体制でも現実的に回せます。まずは影響の大きい業務ルール整合性から着手し、検証SQLを1本ずつ増やしていく進め方が現実的です。

まとめ|不整合を「見える化」する検証を仕組みにする

データの不整合は、画面には現れず、発覚したときには事故になっているという厄介な性質を持ちます。だからこそ、機能が動くかとは別の軸で、データが矛盾していないかを検証するデータ整合性テストを独立した観点として組み込むことが重要です。

本記事で整理した要点を振り返ります。

  • 整合性は「制約」「参照整合性」「業務ルール」の3層で捉え、DB制約で守れない業務ルール層を最も手厚く検証する
  • トランザクションは、ロールバック・同時実行・排他制御を意図的に競合させて確認する
  • 状態遷移は、正しい遷移だけでなく「あり得ない遷移の拒否」と「関連データの同期」を突く
  • バッチは、二重実行と再実行(冪等性)、締め時刻の境界を狙い撃ちする
  • 外部連携は、タイムアウトという「結果不明」状態と、結果整合性の収束を必ず検証する
  • 進め方は、実行前後の突合と「あってはならない状態を検出する検証SQL」を軸にする

これらを一度きりのテストで終わらせず、検証SQLをリグレッションのたびに流せる形に残しておくと、改修による不整合の再発を早期に検知できます。整合性の検証を属人的な勘に頼らず、仕組みとして定着させることが、静かに進行するデータ事故を防ぐ最も確実な近道です。改修のたびに同じ観点を人手で思い出す運用は長続きしません。検証を資産として残し、繰り返し流せる状態にしておくことが、少人数の体制でも品質を保ち続ける鍵になります。

なお、整合性検証は業務ロジックの深い理解と、境界・競合を突くテスト設計の両方を要するため、社内リソースだけでは手が回りにくい領域でもあります。品質への影響が大きいシステムの信頼性確保については、IPAが公開する社会・産業のデジタル変革に関する情報なども参考になります。自社だけでの検証設計に不安がある場合は、テスト体制の見直しについて相談するところから始めてみてください。第三者の視点を入れることで、見落としがちな不整合の観点を補いやすくなります。

次に読むならこの記事

テストの手戻りを減らしたい方へ

テスト仕様書のExcelテンプレートを無料で配布しています。自社で整備する場合も、外部に任せる場合も、まずは型を持つところから。

ソフトウェアテスト代行サービスのご紹介

当社では10万円から始められるソフトウェアテスト代行サービスを提供しています。

テスト専門部隊による品質保証で、開発チームは本来の開発業務に集中できます。
品質向上と納期遵守の両立をサポートし、顧客からの信頼獲得に貢献します。

お問い合わせ

サービスに関するお問い合わせ、ご不明な点がございましたら、以下のお問い合わせフォームをご利用ください。お客様からのご質問に対し、担当者が責任を持ってお答えいたします。

よかったらシェアしてね!
目次
閉じる