1 異常系テストの概要

異常系テストとは、システムやソフトウェアが想定外の入力、状態、操作、または環境変化に直面した際に、適切な検知と安全な制御を行い、妥当なエラー処理や復旧動作を実施できることを確かめるテスト手法である。成功時(正常系)では表面化しにくい「失敗の仕方」や「壊れ方」を対象にするため、信頼性安全性保守性の向上に結びつきやすい。

実務では、境界条件、例外・エラー応答、性能の悪化、タイムアウト、リソース枯渇、依存関係の不調など、破綻につながる要因を意図的に発生させる。期待されるログ通知、リトライやフォールバックロールバックなどが設計どおり機能するかを検証することで、障害時の挙動を予測可能にする。

適用範囲は業務システムから組込み機器、クラウド基盤まで広い。重要度や損害の大きさに応じて網羅性と深さを調整し、優先順位づけを行うことが運用上の要点となる。

1.1 正常系テストとの違い

正常系テストは、仕様どおりに入力が提供され、処理が期待どおり完了することを確認するのが中心である。これに対し異常系テストは、仕様が前提としない入力や状況が来た場合に、どのように失敗を扱うかを検証する。焦点は「成功の再現」ではなく「失敗時の制御」「安全な停止」「回復可能性」に置かれる。

また正常系は再現性比較的高い一方、異常系は実行経路分岐しやすく、外部要因の揺らぎも増える。そのため、観測項目(ログ、メトリクストレース)と期待値(オラクル)を明確に定義し、環境差によるブレを抑える設計が必要になる。

1.2 目的と期待する品質

異常系テストは「異常が起きたら止まる」ことだけを目的としない。検知、応答、復旧の一連の品質を、実装に即して測定可能な形に落とし込むことが重要である。

1.2.1 障害の検知

異常が発生したことを、システムが適切な粒度で認識できる状態を作るのが第一の目標である。例えば入力の不正、通信断、内部例外、整合性違反などを、単なる例外放出で終わらせず、扱えるエラーに変換する必要がある。検知の粒度が粗いと、誤った理由で誤復旧が行われ、逆に危険になる。

さらに、検知が行われたことは、ログ記録や通知、メトリクスの更新など、外部から確認できる手段を通じて示されるべきである。

1.2.2 エラー応答の妥当性

エラー応答の妥当性とは、利用者や呼び出し元に対して、状況に即した結果を返すこと、また内部資源を不整合な状態にしないことを含む。例えば外部APIでは適切なHTTPステータスやエラーメッセージが返され、リトライ可能性や再実行の可否が読み取れる形式であることが求められる。

一方、メッセージ内容は機密情報の漏えいを避ける設計も同時に必要である。ユーザ向けと開発者向けのログを分離する方針などが品質として評価される。

1.2.3 復旧・継続可否の確認

復旧・継続可否の確認は、異常発生後に処理を中断すべきか継続すべきか、あるいは段階的に縮退させるのかを検証する目的を持つ。復旧とは、リトライによる再試行、フォールバック経路への切替、トランザクションのロールバック、キャッシュの再構築などを指す。

重要なのは「復旧したように見える」だけでなく、データ整合性、二重実行の抑止、後続処理への影響範囲が管理されていることを観測可能にする点である。適切な復旧戦略は、障害の規模と許容停止時間に応じて選ばれる。

1.3 対象範囲(機能・非機能)

異常系テストの対象は機能面と非機能面の双方に及ぶ。機能面では、例外時の返却値、状態遷移、整合性維持、権限エラーの扱いなどが該当する。非機能面では、応答時間の劣化、タイムアウト、スループット低下、メモリ上限超過、スレッド枯渇など「品質劣化」を含めて検証する。

機能と非機能は分離されがちだが、現実には連動する。例えばリソース枯渇は性能劣化を招き、結果としてタイムアウトや例外経路が変化するため、境界をまたいだ観点設計が有効になる。

2 テスト観点の設計

テスト観点の設計は、異常の種類を体系化し、どの観測結果をもって「期待どおり」と判断するかを決める工程である。網羅は望ましいが無制限ではないため、リスクの高い組合せから設計に落とす。

2.1 入力起因の異常

入力起因の異常は、外部から与えられる値や入力系列が前提仕様から外れるケースである。形式、値域、順序、重複など、入力の属性に着目して設計するのが一般的である。

2.1.1 無効入力

無効入力には、データの形が崩れている場合と、必要情報が欠けている場合がある。システムが受け取った後に深い処理へ進んでしまうと、影響が広がるため、早期検知が重要になる。

2.1.1.1 形式不正・必須欠落・桁あふれ

形式不正は、パース不能、文字コード違反、想定外のエンコードなどを指す。必須欠落は、必須フィールドが空、欠け、または参照できない状態として現れる。桁あふれは、数値型の上限を超えることで丸めや切り捨て、オーバーフローにつながる。

異常系では、これらを例外として漏らすのではなく、検証エラーとして扱い、利用者に理解可能な範囲でフィードバックすることが求められる。

2.1.2 境界値外れ

境界値外れは、仕様が許容する最小・最大、または区切り条件(期間、長さ、件数、価格帯など)をわずかに超えた値を与えることで成立する。境界周辺は実装の条件分岐が複雑になりやすく、オフバイワンや比較演算の誤りが表面化しやすい。

異常系テストでは「境界の外側」に加えて「境界の内側の最小差」もセットで扱い、誤った受理や誤った拒否を見分けられるようにする。

2.1.3 冗長・重複・順序不正

冗長や重複、順序不正は、入力の意味論に関わる異常である。例えば同一キーの重複、同じ要求の二重送信、配列の順序が仕様と違う、または前提ステップを飛ばした系列の送付が該当する。これらは処理系によっては「受理してしまう」ことが最も危険であり、二重登録や矛盾状態につながる可能性がある。

順序不正は特にステートフルな機能(セッション、ワークフロー、段階処理)で重要であるため、状態遷移の観点と接続して設計するのが有効である。

2.2 状態起因の異常

状態起因の異常は、内部状態や外部依存の状態が前提条件を満たさないときに生じる。入力が正しくても成立するため、状態管理の正確さを測る観点となる。

2.2.1 依存関係の欠落

依存関係の欠落は、必要なサービスやデータが存在しない、参照できない、初期化されていないなどの状態である。例えば設定ファイルが読み込めない、参照先テーブルが欠ける、外部キャッシュが未構築のまま利用されるといった事象が含まれる。

このとき重要なのは、欠落を検知して安全にエラー処理へ遷移できるか、または縮退モードで継続できるかである。単なる「失敗」ではなく、挙動の設計が評価対象になる。

2.2.2 状態遷移の逸脱

状態遷移の逸脱は、許可された手順から外れたタイミングで操作が行われるケースである。例として、ワークフローの途中でないのに完了処理を呼ぶ、未作成の対象に更新をかける、ロック解放前に次段へ進むなどがある。

異常系では、誤った遷移を許さない制御(ガード条件)と、その際の応答が一貫していることを確認する。

2.2.3 同時実行による競合

同時実行による競合は、複数の要求が同一の資源を同時に更新しようとする状況で発生する。競合が生じると、更新の上書き、整合性違反、ロックの取り扱いミスなどにより、見えにくい欠陥が生まれる。

観点としては、楽観/悲観ロックの挙動、整合性例外の扱い、再試行の安全性(二重反映の回避)などを設計に含める。

2.3 外部環境起因の異常

外部環境起因の異常は、ネットワーク、ストレージ、設定、権限、周辺資源など、システム外の要因で起こる。発生確率は低くても、実運用では十分起こり得るため、再現可能な形で検証する価値が高い。

2.3.1 ネットワーク断・遅延

ネットワーク断は接続の喪失、遅延は応答到達までの時間延長を意味する。タイムアウト設定、リトライ戦略、切断検知のタイミングが品質を左右する。遅延があると、単純な処理時間の増大にとどまらず、順序保証やリソース保持時間にも影響する。

異常系では、タイムアウト後に後続処理が破綻しないこと、未完了処理の扱いが明確であることを観測する。

2.2.2 ストレージやリソース枯渇

ストレージやリソース枯渇は、ディスク容量不足、ファイルハンドル上限、メモリ制約、スレッドプールの枯渇、キュー滞留などとして現れる。枯渇は段階的に顕在化し、最初は性能劣化として始まり、やがて例外経路へ移行する。

重要なのは、枯渇時に安全停止、縮退、回収(リソース解放)などが設計どおりかどうかである。リークが残っていると、短い時間で再現性のある障害となるため、回復可能性も評価対象になる。

2.2.3 設定変更・権限不足

設定変更や権限不足は、運用上の変更で偶発的に起こり得る異常である。例えば設定値の形式が想定と異なる、権限のロールが欠ける、読み取り専用化により書き込みが失敗するなどが該当する。

この種の失敗は、再試行しても解消しない場合が多い。したがって、エラー内容が原因究明に資する形で記録され、利用者への応答が誤作動を招かないことが期待品質となる。

2.4 業務ルール起因の異常

業務ルール起因の異常は、仕様が定める整合性や制約に反するケースである。入力の形式は正しくても、業務上の条件を満たさないことでエラーが生じる点が特徴である。

2.4.1 承認・整合性制約

承認や整合性制約は、例えば承認済み状態でしか処理できない、金額や数量の整合が必要、期限や優先度が条件に含まれるなどの形で現れる。異常系では、制約違反がシステム内部で適切に検知され、誤った状態更新を伴わずに拒否できるかが焦点となる。

エラー応答は、利用者が次に取るべき行動(修正、再申請、確認)に結びつく情報を含むことが望ましい。

2.4.2 参照整合性の破綻

参照整合性の破綻は、外部キーや参照先の存在、参照範囲の妥当性が崩れることで起こる。典型的には、参照先が削除されているのに参照を継続する、または参照先が別の契約単位に属しているなどがある。

検証はデータレベルだけでなく、業務コンテキスト(利用可能範囲)に沿って行う必要がある。破綻を見逃すと、データの混線や後工程の誤判定につながり得る。

2.4.3 削除・更新競合

削除・更新競合は、ある操作と別の操作が近い時刻に行われ、前提となるデータ状態が変化してしまう状況である。例えば削除後に更新を受ける、更新中に前提行が消える、版(バージョン)が競合するなどが該当する。

異常系の観点では、楽観ロックの失敗時処理、競合解決の方針(再取得して再計算、ユーザへの再入力促しなど)が一貫していることを確認する。

3 実施手順と手法

実施手順は、ケース設計から実行、観測、再現性確保、結果整理までの流れとして整理される。異常系では「何を見れば期待どおりか」を先に決めることが特に重要である。

3.1 テストケース作成

テストケース作成では、異常の入力・事前状態・手順・期待観測をセットで定義する。入力起因と状態起因、外部要因が絡む場合は、どこまでをテストの責務として切り出すかを明確化する。

また単発のケースだけでなく、複数異常を段階的に重ねる設計も有効である。例えば遅延を増やした上でタイムアウトを発生させるなど、現実に近い順序を再現する。

3.2 期待結果(オラクル)の定義

オラクルは、テストが合格か不合格かを判定する基準である。異常系では「ログに出れば良い」など曖昧な基準を避け、返却、例外、状態変化、回復動作まで定量・定性の両面で定義する。

3.2.1 エラーメッセージ

エラーメッセージは利用者向けと開発者向けに分けて扱う方針が望ましい。利用者向けは意味が伝わり、不要な内部情報を含まないこと。開発者向けログは原因追跡に必要な識別子や文脈を備えることが評価対象となる。

文字列完全一致ではなく、コード(エラー種別)やカテゴリの一致を採用することで、UI文言変更に強い判定にできる。

3.2.2 HTTPステータス等の応答

通信型の機能では、HTTPステータスや独自応答コードが期待どおりになるかを確認する。加えて、レスポンスボディに含まれるフィールド、リトライ可能性の示唆、ヘッダの整合も観測する。

ステータスの種類だけでなく、同じ異常でも呼び出し元の状態によって応答が変わる場合があるため、前提条件をテストケースに明記する。

3.2.3 ログ・トレース

ログ・トレースは、異常発生点、検知の根拠、処理経路、復旧判断、外部呼び出し失敗の詳細などを追跡できるように設計する。相関IDや要求IDにより、複数コンポーネントに跨る観測が可能になることが望ましい。

またログが過剰に出るとノイズとなる。重要イベントに絞る方針を採り、異常系で必要な最低限の粒度が実現されているかを確認する。

3.2.4 復旧動作(リトライ・フォールバック)

復旧動作のオラクルは、再試行回数や待機時間、打ち切り条件、バックオフの有無、フォールバックの選択理由を含む。例えば依存サービスが一時的に落ちた場合に限りリトライし、恒久的なエラーでは即時に中断するなど、判断の一貫性が求められる。

フォールバックでは、結果がどの経路で作られたかを判別できるメタ情報(経路ラベル)を残すと、判定の確度が高まる。

3.3 テストデータと前準備

テストデータと前準備では、異常入力そのものだけでなく、異常が成立するための事前状態を整える。

3.3.1 異常データの生成

異常データの生成は、形式不正、境界逸脱、重複、矛盾する組合せなどを意図的に作る作業である。生成器を用いる場合は、対象フィールドごとの制約を反映させ、現実の誤入力に近い形で作成する。

外部連携がある場合、プロトコル違反の模擬方法(ヘッダ不整合、ボディ破損)も含めて準備する。

3.3.2 事前状態の構築

事前状態の構築では、必要なレコード、セッション、設定値、権限などを整える。さらに競合を作るケースでは、別プロセスやスレッドを用いた同時実行の設計が必要となる。

基盤環境では、タイミング依存の失敗が起きやすい。そこで状態構築と開始の同期(バリアなど)により、再現性を高める工夫が求められる。

3.4 実行と観測(計測)

実行と観測では、異常時に得られる情報が合否判定に直結するため、計測項目を事前に定める。観測が不足すると、期待外れの原因が特定できず再実行のコストが上がる。

3.4.1 監視指標の確認

監視指標の確認は、CPU、メモリ、応答時間、エラー率、キュー長、外部呼び出し失敗率など、非機能の変化を把握するために行う。異常系では「期待どおりに失敗した」ことだけでなく、システム全体が破綻していないか(波及していないか)も確認する必要がある。

許容範囲を超える指標が観測された場合、機能面の期待どおりでも非機能面の品質問題として扱う。

3.4.2 失敗時の収集項目

失敗時の収集項目には、エラーコード、スタックトレース(機密に配慮)、トランザクションID、使用した設定、依存先の応答、リトライ回数などが含まれる。さらに、復旧が行われた場合は、ロールバックの有無やデータ差分の結果も追跡する。

収集項目は過不足があると機能する分析に欠ける。重要度に応じて優先順位を設け、必要なものだけを確実に残す。

3.4.3 再現性の担保

再現性の担保は、タイミングや乱数、環境差によるブレを抑えることである。乱数シードの固定、時計のモック、外部サービスのスタブ化、ネットワーク遅延の制御などが代表例である。

また失敗が揺れる場合は、統計的な観測だけに頼らず、条件を絞って決定論的な再現へ寄せる。これにより不具合の原因特定が容易になる。

4 よくある異常パターン

本章では、異常系テストで頻出しやすいパターンを整理する。個別の事象名は違っても、設計上の共通課題(検知、応答、復旧、安全性)が現れる。

4.1 タイムアウトとキャンセル

タイムアウトは、応答が指定時間内に来ないときに処理を中断する仕組みである。キャンセルは、実行中の処理を取り消す要求が来たときに整合を保って停止することを指す。どちらも中途状態の扱いが難しく、リソース解放や後続処理の防止が品質を左右する。

異常系では、タイムアウト発生後に重複処理やデータ二重更新が起きないこと、キャンセル後に外部呼び出しがリークしないことを確認する。

4.2 例外処理とフォールバック

例外処理は、予期しない事態を捕捉し、エラーとして整形し、利用者や呼び出し元に伝える仕組みである。フォールバックは、その例外に対する代替経路の利用であり、可能な範囲でサービス提供を継続する。

ただしフォールバックが誤作動すると、誤情報の配信や整合性破壊につながる。異常系テストでは、フォールバックの条件が正しいか、復旧後に整合性が回復しているかを観測する。

4.3 冪等性が崩れるケース

冪等性とは、同じ要求を複数回実行しても結果が変わらない性質を指す。冪等性が崩れると、再試行やネットワーク再送の際に二重反映が起きる。

崩れやすい要因として、更新と副作用(外部通知、在庫引当、メール送信)が分離されていない、または重複検知が要求識別子に依存しすぎることが挙げられる。異常系では、リトライ時の二重実行防止が機能しているかを確認する。

4.4 リソースリーク・枯渇

リソースリークは、使用後に解放されないメモリ、ハンドル、接続などが蓄積していく状態である。枯渇は、それが限界に到達して処理停止や例外を引き起こす段階である。

異常系テストでは、失敗時の後処理(クリーンアップ)が欠けていないか、負荷をかけたときにしきい値で安全に縮退するかを観測する。単発の動作では見えにくいため、複数回繰り返した結果も重要になる。

4.5 故障注入(障害シミュレーション)

故障注入は、意図的に障害状態を作り、システムの耐性と復旧挙動を評価する方法である。手法は、環境上の切替(ネットワーク制御、依存サービス停止)やデータ異常の模擬などに分かれる。目的は「たまたま起きた障害」を待たずに、条件を再現しやすくすることにある。

4.5.1 ネットワーク遮断

ネットワーク遮断は、依存先との通信路を遮断して呼び出しの失敗経路を通すことである。遅断や部分遮断を含めると、タイムアウトやリトライの判断をより現実に近い形で検証できる。

観測としては、遮断後の応答時間、エラーコード、再試行回数、復旧時に回復するかを中心に設定する。

4.5.2 計測・依存サービス停止

依存サービス停止は、外部API、データストア、メッセージング基盤などを止めて、内部の依存呼び出しを失敗させる。計測基盤が停止する場合は、ログやトレースが欠ける可能性もあるため、観測性の低下が品質評価に影響しないよう設計する必要がある。

内部側で代替ログや最低限のエラーハンドリングが働くかを異常系で確かめる。

4.5.3 データ破損の模擬

データ破損の模擬は、整合性が壊れた状態(欠損フィールド、異常な値、矛盾した参照)を作って読み取りや更新の失敗挙動を評価する。ここでは、破損を受け取った際にどの段階で検知されるかが重要である。

復旧では、破損データの隔離や再構築、または安全な拒否が適切に行われることが期待される。

5 成果物・管理

成果物と管理は、テストを個別の実行に留めず、リスク低減へつなげるための枠組みである。計画、記録、分析、再発防止が循環することが望ましい。

5.1 テスト計画とリスク優先度

テスト計画では、異常系の対象を決め、優先度と範囲を定義する。リスク優先度は、障害時の影響度(被害規模、損失、停止時間)と発生可能性(外部依存、変更頻度)から決める。

全ケースを網羅するのではなく、重要な経路と重大な失敗を優先し、必要に応じて段階的に拡張する方針が現実的である。

5.2 実行記録とレポート

実行記録とレポートでは、テストの実施状況、結果、観測された事象を整理する。異常系では「失敗した理由」を追える情報が必要であり、ケースごとの前提状態と環境条件の記録が価値になる。

5.2.1 合格基準・不合格基準

合格基準・不合格基準は、オラクルに基づいて具体化する。例えばエラー応答のカテゴリ一致、ロールバックの実施、リトライの上限内、ログの必須項目の出現などを合格要件とする。

不合格基準は単に例外発生を含めず、データ不整合や二重実行などの危険な結果を明確に含める。

5.2.2 重大度の付与

重大度は、見つかった不具合が安全性や業務継続に与える影響の大きさで決める。異常系では、見かけ上はエラーとして返っていても、内部状態が壊れている場合があるため、影響範囲を評価に入れる。

重大度の分類を統一することで、修正の優先順位と再テスト計画が合理化される。

5.3 不具合分析と再発防止

不具合分析は、観測結果と実装の分岐を突き合わせ、原因を体系化して再発を防ぐことを目的とする。異常系の価値は、単なる検出ではなく、設計と実装の改善へつなげる点にある。

5.3.1 原因分類(起因・影響)

原因分類では、起因(入力、状態、依存、環境)と影響(データ整合性、可用性、セキュリティ、観測性)を分けて整理する。起因が同じでも影響が異なる場合があり、修正方針が変わる。

また二次影響(波及)を考慮し、単体コンポーネントの問題ではない場合は、システム設計の見直しへ結びつける。

5.3.2 修正方針と回帰

修正方針では、検知の早期化、エラー変換、復旧戦略の調整、ガード条件の追加、冪等性の改善などから選択する。修正が仕様に反する場合は仕様側の見直しも検討対象になる。

回帰では、修正点に関連する異常系ケースに加え、成功系が壊れていないかの確認も含める。異常系の改善は分岐を増やしやすいため、影響範囲の見積もりが重要となる。

6 参考:異常系テストの実例と注意点

本章では、実務に近い形で異常系テストを捉えるための例と、実施時に起こりやすい問題点を示す。

6.1 APIに対する異常系テスト例

APIでは、無効入力、権限不足、依存先タイムアウト、外部応答の形式不正などが典型である。例えば必須フィールド欠落時に適切なエラーコードが返り、状態更新が行われないことを確認する。

また、同じ要求を再送しても二重登録が起きないことを、冪等キーや重複排除の設計に沿って検証する。応答の整合性に加えて、ログに相関IDが含まれているかも確認する。

6.2 バッチ処理の異常系テスト例

バッチ処理では、データ破損、途中失敗、部分完了、再実行時の整合性が焦点になる。例えばレコードの一部が不正であっても、処理単位の設計に従ってスキップまたは隔離し、全体が停止しない挙動を確認する。

途中で失敗した場合は、再実行時に重複効果がないこと、進捗管理が正しく更新されることが重要になる。結果ファイルや集計テーブルの状態も観測対象となる。

6.3 画面・入力フォームの異常系テスト例

画面・入力フォームでは、形式不正、境界逸脱、入力補完の欠落、連続送信による競合などが出発点になる。フロントエンドでバリデーションするだけでなく、サーバ側でも同等の検証が行われるかを異常系で確かめる。

さらに、ネットワーク切断や送信失敗時に再送されてもデータが二重反映されないこと、ユーザへのメッセージが適切に表示されることも確認する。

6.4 よくある落とし穴(過剰期待・再現性不足)

落とし穴として過剰期待がある。例えば「必ず同じログ文言が出る」など細部に依存した判定は、運用変更で崩れやすい。判定はコードやカテゴリの一致など、安定した指標に寄せるべきである。

再現性不足も頻出する。タイミング依存の障害や外部サービスの揺らぎが原因で、毎回同じ結果にならない場合がある。この場合は故障注入の条件を制御し、同期やモックで環境差を減らす設計が必要になる。さらに、失敗が揺れるケースは条件を絞って決定論的に再現できるように調整する。