AIでテストケースを作るときは、実装から期待値を写す前に、要件を入力・前提・期待結果へ分けます。今のコードと同じ答えを返すテストだけでは、そのコードの条件順が間違っていても成功する場合があります。
この記事では、架空の資料出力判定を3条件・8組合せの表にし、要件と対応づけます。正しい判定例と、条件の優先順位を誤った例を同じ期待値で検査します。コード、仕様、テストは手製で、AI生成や実アプリの動作を検証したものではありません。
目次
まず要件と、未確定な条件を分ける
今回の入力は、素材あり、確認済み、PDF希望の三つで、すべてTrueまたはFalseです。判定は文字列を返すだけで、実際にファイルを作りません。次の優先順位を、この例の仕様として固定します。
表は横にスクロールできます
| 要件ID | 条件 | 期待する判定 |
|---|---|---|
| R01 | 素材がない | ほかの条件によらずNO_SOURCE |
| R02 | 素材があり、確認が済んでいない | NEEDS_REVIEW |
| R03 | 素材があり、確認済みで、PDF希望 | |
| R04 | 素材があり、確認済みで、PDF希望ではない | DOCX |
実際のアプリの仕様ではありません。素材がなくても確認済みフラグがTrueという入力は、この例ではR01を優先します。「そんな組合せは来ない」と除くなら、入力側がその状態を防ぐ仕様と検査が必要です。
空欄、文字列の"false"、数値0、通信エラー、実ファイルの失敗は、今回の二値の入力モデルに含めません。対象外であることを残し、8組合せが全部通ったことを、それらの確認へ広げないようにします。
期待値を、実装とは別に表へ書く
3条件が二値なら、組合せは2×2×2=8通りです。この例ではすべてを表へ並べ、どの要件で期待値を決めたかを記録します。
表は横にスクロールできます
| ケース | 素材あり | 確認済み | PDF希望 | 期待値 | 根拠 |
|---|---|---|---|---|---|
| T01 | False | False | False | NO_SOURCE | R01 |
| T02 | False | False | True | NO_SOURCE | R01 |
| T03 | False | True | False | NO_SOURCE | R01 |
| T04 | False | True | True | NO_SOURCE | R01 |
| T05 | True | False | False | NEEDS_REVIEW | R02 |
| T06 | True | False | True | NEEDS_REVIEW | R02 |
| T07 | True | True | False | DOCX | R04 |
| T08 | True | True | True | R03 |
「PDF希望ならPDF」の正常例だけを作ると、T02、T04、T06の優先条件を見逃します。各行を要件へ戻して確認してから、テストコードへ移します。期待値が決まらない行は、現在の実装結果で埋めず、仕様の確認事項にします。
条件数が多い実機能へ、無制限に全組合せを増やす必要はありません。重要な条件、実行可能な組合せ、制約、失敗時の影響を整理します。数値や日付がある場合は、その最小・最大の直前、ちょうど、直後などを、定義した境界に合わせて別に追加します。
小さなコードで、表の期待値と照合する
次は上の架空仕様に合わせた参照用の判定と検査です。入力は三つのboolだけとし、実アプリのファイル処理は呼び出しません。
def decide_export(has_source, reviewed, wants_pdf):
if not has_source:
return "NO_SOURCE"
if not reviewed:
return "NEEDS_REVIEW"
return "PDF" if wants_pdf else "DOCX"
cases = [
("T01", (False, False, False), "NO_SOURCE"),
("T02", (False, False, True), "NO_SOURCE"),
("T03", (False, True, False), "NO_SOURCE"),
("T04", (False, True, True), "NO_SOURCE"),
("T05", (True, False, False), "NEEDS_REVIEW"),
("T06", (True, False, True), "NEEDS_REVIEW"),
("T07", (True, True, False), "DOCX"),
("T08", (True, True, True), "PDF"),
]
for case_id, inputs, expected in cases:
actual = decide_export(*inputs)
assert actual == expected, (case_id, expected, actual)
print("8 cases passed")
このコードはローカルで実行し、8件の期待値と一致しました。ここで確認したのは、手製の判定例と表の対応です。実際のPDFやDOCXを作れること、保存先へ反映されること、画面が正しく案内することは確認していません。
実プロジェクトへ取り込む場合は、その言語・テストフレームワーク、既存の命名、fixture、依存先の置き換え方へ合わせます。GitHubの公式テスト作成ガイドも、対象条件を指定し、生成テストを実行・レビューする流れを説明し、生成案が全シナリオを覆うとは限らないとしています。GitHub公式:テスト作成(新しいタブで開く)
条件順の誤りを、同じテストで見つける
次は、誤りの説明用に作った別の判定例です。PDF希望を先に見てしまい、素材や確認状態を飛ばします。実サービスで発生した不具合や、AIが生成した結果ではありません。
def wrong_export(has_source, reviewed, wants_pdf):
if wants_pdf:
return "PDF"
if not has_source:
return "NO_SOURCE"
if not reviewed:
return "NEEDS_REVIEW"
return "DOCX"
この誤った例を、同じ8件の期待値へ当てると、次の3件が合いません。ローカルで両者を実行して確認しました。
表は横にスクロールできます
| ケース | 要件から決めた期待値 | 誤った例の結果 | 問題 |
|---|---|---|---|
| T02 | NO_SOURCE | 素材がない条件を飛ばす | |
| T04 | NO_SOURCE | 素材がない条件を飛ばす | |
| T06 | NEEDS_REVIEW | 確認前の状態を飛ばす |
5件が合っていても、この仕様への適合とは判断できません。失敗を消すために期待値をPDFへ変えるのではなく、R01・R02と照合します。逆に要件そのものが変わったなら、仕様変更として記録し、表とテストを一緒に更新します。
この例の誤りが見つかったことは、すべての不具合を検出できる証拠ではありません。テストが何を見逃すかも、入力モデルと実際の依存先へ戻って考えます。
AIへの依頼は、ケース表とコード生成を分ける
要件からテストケース案を作ってください。
最初にコードを作らず、次の表を出してください。
ケースID|前提|入力|操作|期待結果|要件ID|未確定事項。
既存実装の返り値を、そのまま期待値の根拠にしないでください。
複数条件が重なるときは、仕様上の優先順位を示してください。
未定の動作や入力は、推測せず確認事項にしてください。
対象に必要な正常系・異常系・境界・状態・依存先失敗を選んでください。
ケース表の確認後、既存のテストフレームワークへ合わせたコード案を作ります。
生成と実行と結果確認は区別してください。
入力:[要件、対象コード、既存テスト例、対象外の条件]
コード生成後は、表のどの行がどの検査に対応するかを照合します。存在しないAPIやfixtureを使う、テストをskipする、期待する値を実装へ合わせて弱める、といった変更が混ざっていないかも見ます。
失敗した場合は、テストの誤り、実装の誤り、環境の不足、仕様の未確定を分けます。今回のような純粋な判定と、DB保存や外部サービスへの送信を含む操作では、必要な確認が異なります。
実際の機能では、戻り値以外も確認する
保存や送信がある機能では、失敗時に何を変更しないか、再試行で重複しないか、利用者へどの状態を示すかも要件に含めます。mockが成功を返したことだけで、実サーバーへ反映されたとは扱いません。外部APIの応答例を作る工程は、利用する仕様と実行条件に合わせて別に確認します。
実データや認証情報を、そのままテスト用の入力やログへ混ぜません。架空のfixtureを使い、既存のテスト手順で再現できるようにします。コードカバレッジの数値だけでなく、重要な期待結果を実際に確認しているかを見ます。
渡す成果物は、要件の版、ケース表、未確定事項、テストコード、実行条件、結果です。「コードを書いた」「実行した」「期待結果と一致した」を分け、対象外の範囲も残すと、次の修正で同じ根拠を使って確認できます。
参考資料
公式のテスト作成資料の確認日:2026年10月20日。仕様、コード、8ケースは手製の架空例です。参照判定と誤った判定をローカルで実行しました。AI生成、実アプリ、ファイル出力、保存・送信、画面表示は検証していません。
