AI にテストを書かせると、AI は「問題ありません」と言います。
そこで多くの人が次にやることは決まっています。別の AI にレビューさせることです。
ただ、それは独立したレビューになっているのでしょうか。そして、そもそも何が抜けているのでしょうか。
この記事では、AI に素でテスト仕様書を書かせ、それを規格に沿って機械的に監査するところまでを実際にやります。そのうえで、AI による独立レビューがどこまで成立して、どこから成立しないのかを整理します。
先に結論を4つ書きます。
- AI が書いたテスト仕様書は、思ったよりよくできていました。 78件、境界値も決定表も状態遷移表も自作してきます
- それでも規格で測ると、4技法の平均で 63.12% でした。 78件に26件の指摘が付きました
- 抜ける場所に、はっきりした型がありました。 valid は書くが invalid が抜ける。上限は書くが下限が抜ける。条件を1つずつしか動かさない
- そして、同じ文書のカバレッジが基準を変えると 100% にも 25% にもなりました
検証環境: Windows 10 / Claude Code 2.1.239 / Claude Opus 5
まず、AI に素でテスト仕様書を書かせた
題材は「ファイル添付機能」です。要件定義書は31行だけ書きました。
### F01-01 ファイル形式
添付できるのは PDF / PNG / JPEG のみ。
### F01-02 ファイルサイズ
1ファイルあたり 10MB まで。10MB を超える場合は送信前に拒否する。
### F01-03 同時添付数
一度に選択できるのは 5 ファイルまで。
### F01-04 ロールによる制限
| ロール | 許可形式 | 同時添付数 |
|---|---|---|
| 一般 | PDF のみ | 3 |
| 編集者 | PDF / PNG / JPEG | 5 |
| 管理者 | すべて | 5 |
### F01-05 添付の状態
未選択 → 選択済 → 送信中 → 完了 / 失敗
これを渡して、こう頼みました。
テスト仕様書を作成してください。実務でそのまま使える粒度で書いてください。
テスト技法は一切指示していません。 「同値分割を使え」とも「境界値を押さえろ」とも言っていません。素の実力を見たかったからです。
返ってきたのは78件
結果は78件のテストケース、21,708字でした。しかも中身が良い。
| TC-020 | F01-02 | 10,485,759 byte(上限 -1 byte)を添付 | 受理され、エラーは出ない |
| TC-021 | F01-02 | 10,485,760 byte(上限ちょうど)を添付 | 受理される |
| TC-022 | F01-02 | 10,485,761 byte(上限 +1 byte)を添付 | 拒否され、エラーが表示される |
10MB を byte に展開して、上限の前後を押さえています。 指示していません。
それだけではありません。
- デシジョンテーブル(ロール × 形式 × 件数 × サイズ)を自分で作った
- 状態遷移表を自分で作った
- 要件定義書の矛盾を6件指摘してきた(「F01-01 は PDF/PNG/JPEG のみと書いてあるが、F01-04 の管理者は『すべて』となっていて矛盾する」など)
矛盾の指摘は正しいものでした。私が要件を書くときに埋め込んでしまった穴です。
「AI は雑なテストを書く」という前提は、ここで崩れます。 むしろ人間が急いで書いたものより整っています。
だからこそ、この記事の問いが成立します。この出来のものを、規格に沿って機械的に走査したら何が残るのか。
AI が自分のテストをレビューすると、何が起きるか
監査の話に入る前に、なぜ「AI にレビューさせる」だけでは足りないのかを押さえます。
2024年に出たこの論文が、直接の答えを持っています。
- Konstantinou, M., Degiovanni, R., Papadakis, M.
"Do LLMs generate test oracles that capture the actual or the expected program behaviour?"
arXiv:2410.21136 [cs.SE], 2024-10-28
24 のオープンソース Java リポジトリを使った統制実験で、LLM ベースのテスト生成手法もまた、「期待される動作」ではなく「実際の動作」を捉えるオラクルを生成する傾向があると報告しています。
これは重い指摘です。
テストの期待値(オラクル)が実装の写しになるということは、実装に欠陥があれば、その欠陥をそのまま正解として固定してしまうということです。バグのあるコードを見て「このコードはこう動く」を期待値に書けば、テストは通ります。通りますが、何も検証していません。
そして「問題ありません」と報告されます。
この構造の中で、期待値の妥当性判定まで LLM に委ねると、検証そのものが成立しなくなります。
別の AI に見せても、独立にはならない
では、書いた AI とは別の AI にレビューさせればよいのでしょうか。
ここで規格を見ます。ISTQB の Foundation Level シラバス(v4.0.1、2024-09-15)は、独立性を4段階に分けています。
Work products can be tested by their author (no independence), by the author's peers from the same team (some independence), by testers from outside the author's team but within the organization (high independence), or by testers from outside the organization (very high independence).
(成果物は、その作成者自身によってテストされることもあれば(独立性なし)、同じチーム内の同僚によって(ある程度の独立性)、作成者のチーム外だが組織内のテスターによって(高い独立性)、あるいは組織外のテスターによって(非常に高い独立性)テストされることもある)
なぜ独立性が効くのかも、同じ節に書かれています。
A certain degree of independence makes the tester more effective at finding defects due to differences between the author's and the tester's cognitive biases (cf. Salman 1995).
(ある程度の独立性があると、作成者とテスターの認知バイアスの違いによって、テスターは欠陥をより効果的に見つけられるようになる)
効いているのは「別人だから」ではありません。「認知バイアスが違うから」です。
ここが分かれ目になります。同じモデル、同じプロバイダ、同じ API キーで動く2つのエージェントは、別人ではありますが、認知バイアスは共通しています。
同じ節にはこうも書かれています。
Independence is not, however, a replacement for familiarity, e.g., developers can efficiently find many defects in their own code.
(ただし独立性は、精通していることの代わりにはならない。たとえば開発者は自分のコードの中の欠陥を効率よく見つけられる)
独立性は万能ではないとも規格は言っています。
自分たちの位置を正直に決める
この4段階に、AI エージェントによるレビューを当てはめるとどうなるか。
| ISTQB の段階 | AI で言うと |
|---|---|
| 作成者本人(no independence) | 同じセッションで書かせて、そのままレビューさせる |
| 同じチームの同僚(some independence) | 別のサブエージェント。ただし同一プロバイダ・同一 API キー |
| チーム外・組織内(high independence) | — |
| 組織外(very high independence) | 別プロバイダの LLM、あるいは人間 |
サブエージェントを分けて到達できるのは、2段目までです。
私たちはこれを EWSI(Enhanced Within-Session Independence) と呼んで、達成できるものとできないものを表に固定しました。
| 独立性の側面 | 達成 | 理由 |
|---|---|---|
| 構造的な独立 | 達成 | コンテキスト分離 / 権限制限 / セッション破棄 / 親の判断を引き継がない |
| Managerial Independence | N/A | 同一プロバイダ・同一 API キー。プロバイダ由来のバイアスは共通 |
| Financial Independence | N/A | 同じ予算プールから動く |
「AI に独立レビューさせています」と言い切らないための表です。名乗れるのは2段目まで、と決めておく。
循環を断つ発想:判断させず、数えさせる
ここからが設計の話です。
オラクルが実装の写しになる問題は、AI に「これは正しいか」を判断させている限り消えません。 別のエージェントに聞いても、バイアスが同じなら同じ答えが返ってきます。
そこで方針を変えます。
判断させるのをやめて、数えさせる。
「このテストは妥当か」は聞きません。代わりに聞くのはこれです。
- 同値クラスは全部あるか。valid だけでなく invalid も
- 境界値は全部あるか。上限だけでなく下限も
- 決定表の規則は全部あるか。組合せは何通りで、何通り書かれているか
- 状態遷移は全部あるか。表に書いた遷移に、対応するテストがあるか
これらは数えれば答えが出ます。 主観が入りません。規格が「何を数えるか」を決めてくれているからです。
入れなかったものが3つある
設計を語るには、入れたものより外したものの方が雄弁です。
| 外したもの | 理由 |
|---|---|
| LLM Oracle(期待値の妥当性そのものを判定させる) | 先の論文の指摘そのもの。同一プロバイダでは検証が成立しない |
| Combinatorics(Pairwise / 直交表) | PICT や ACTS など外部ツールの統合が前提。LLM に計算させる話ではない |
| Aggregator(集約役のエージェント) | 集約は指揮側の仕事。エージェントにする必要がない |
一番効きそうな LLM Oracle を、最初に外しています。 効きそうに見えて、構造的に成立しないからです。
技法ごとにエージェントを分ける
残った「数えられるもの」を、技法ごとに別のエージェントへ割り当てます。
指揮役(採点しない。集約だけ)
├─ EP 同値分割 ISTQB FL §4.2.1
├─ BVA 境界値分析 ISTQB FL §4.2.2
├─ DT 決定表 ISTQB FL §4.2.3
├─ ST 状態遷移 ISTQB FL §4.2.4
└─ Dedup 重複検出 ISO/IEC 29119-4
ISTQB FL v4.0.1 の §4.2 は、ブラックボックス技法としてこの4つを挙げています。だから4つに分けています。分割は恣意ではなく、規格の目次に従っただけです。
分けることには実利があります。1つのエージェントに「テスト設計を全部見て」と頼むと、見落とします。 技法を1つに絞れば、そのエージェントは他を気にせず、その技法だけを最後まで数えられます。
独立性を構造で担保する4つの手段
各エージェントには制約をかけています。
1. 権限を read-only にする。 使えるツールは Read / Grep / Glob だけです。Edit も Write も渡しません。 自分で仕様書を直せてしまうと、「直したから問題なし」が成立してしまいます。
2. 親のコンテキストを引き継がせない。 プロンプトに毎回こう書いています。
親セッションの判断は一切引き継がないこと。
ファイルとモデルの証拠のみで判定してください。
3. 指揮役から採点権限を取り上げる。 指揮役(私が動かしているセッション)は、仕様書を読んで自分で網羅判定してはいけないというルールにしています。やるのは集約だけです。ここを緩めると、結局1つのコンテキストで書いて採点することになります。
4. 全ての指摘に行番号を付けさせる。 「境界値が足りない気がします」は通しません。どのファイルの何行目かを必ず添えさせます。
実測:78件を監査したらどうなったか
前置きが長くなりました。実際に走らせます。
結果
技法 基準 網羅 カバレッジ 判定 P0
------------------------------------------------------------------
EP 同値分割 12/14 85.71% FAIL 2
BVA 境界値分析 13/18 72.20% CONDITIONAL 0
DT 決定表/all_rules 18/72 25.00% FAIL 3
ST 状態遷移 16/23 69.57% FAIL 1
Dedup 重複検出 3000/3003 99.90% CONDITIONAL 0
------------------------------------------------------------------
4技法の単純平均 63.12%
P0 6件 / P1 9件 / P2 11件 総合判定: FAIL
78件のテストケースに、26件の指摘が付きました。
以下、何が出たかを技法ごとに見ます。どれも人間のレビューでは見つけにくいものでした。
EP:合否が判定できないテストケース
AI は 0 byte のファイルを試すテストをちゃんと書いていました。問題は期待結果です。
拒否されるか、または受理される場合も送信後に破損データが残らない
これでは実行しても PASS / FAIL が決まりません。
しかもこれは「AI がサボった」のとは違います。要件定義書に 0 byte の扱いを書いていないので、AI は誠実に「未確定である」と表現したとも読めます。実際、別項で「要件の確認事項」として挙げてもいました。
それでも、テスト仕様書としては欠陥です。レビューで「0 byte のケース、ちゃんとありますね」と読み飛ばされる形をしているところが厄介です。
もう1件は分かりやすい欠落でした。一般・編集者・管理者の3ロールは完全に網羅されているのに、未認証やロール未割当のリクエストを試すテストが1件もありません。
valid は全部書く。invalid が抜ける。 同値分割で最も典型的な穴です。
BVA:上限は完璧、下限がない
境界値はこうなっていました。
10,485,759 byte(上限 -1) ある
10,485,760 byte(上限) ある
10,485,761 byte(上限 +1) ある
1 byte(下限) ない
一番小さいテストが 1,024 byte で、下限そのものを検証していません。 件数でも、1件・4件・5件・6件はあるのに2件(中間値)がありません。
ここで規格を見ると、はっきり書いてあります。
The minimum and maximum values of a partition are its boundary values.
(パーティションの最小値と最大値が、その境界値である)
minimum も maximum も境界値です。 AI は maximum しか見ませんでした。
理由は要件定義書を読み返すと分かります。私はこう書いていました。
1ファイルあたり 10MB まで。10MB を超える場合は送信前に拒否する。
「10MB」という数字は書いてあります。だから上限は徹底的にテストされました。 一方、「1 byte 以上」とはどこにも書いていません。だから下限は見られませんでした。
AI は要件の文字列に忠実で、要件が言及していない領域には踏み込みません。 境界値分析は本来「範囲には両端がある」という技法なので、規格に照らすと片側しか適用されていないことになります。
なお ISTQB は BVA を2種類に分けています。ここは用語が紛らわしいので原文を引きます。
In 2-value BVA (Craig 2002, Myers 2011), for each boundary value there are two coverage items: this boundary value and its closest neighbor belonging to the adjacent partition.
(2-value BVA では、各境界値につき2つのカバレッジ項目がある。その境界値と、隣接パーティションに属する最も近い隣接値である)
In 3-value BVA (Koomen 2006, O'Regan 2019), for each boundary value there are three coverage items: this boundary value and both its neighbors.
(3-value BVA では、各境界値につき3つのカバレッジ項目がある。その境界値と、その両隣である)
2-value が見るのは「境界値」と「その外側」です。内側ではありません。 ここは私自身が実装側で取り違えていて、記事を書く前の確認で見つけました(後述します)。
ST:自分で「不可」と書いて、それを試していない
一番効いたのがこれです。
AI は状態遷移表を自作していました。その中にこう書いてありました。
送信中 × 送信 → 不可(二重送信禁止)
この行にだけ、テストケース番号が引かれていませんでした。 同じ表の他のセルには TC 番号があるのに、ここだけ空欄です。78件を全部見ても、二重送信を試すテストが存在しません。
表には書いた。テストは書かなかった。
二重送信はデータ整合性に直結するので、最優先の欠落として扱われました。
さらに、自分の表と自分のテストが食い違っている箇所もありました。
| どこ | 何と書いてあるか |
|---|---|
| 状態遷移表 | 失敗 → 送信 → 送信中(直接) |
| テストケース | 失敗 → 選択済 → 送信中(2段階) |
同じ文書の中で矛盾しています。 どちらかが誤りですが、通読して気づくのは難しい。
他にも、表に書いてあるのに対応するテストがない遷移が4本(失敗からのファイル選択、失敗からの全削除、完了からのファイル選択、選択済の自己遷移)ありました。
表を作る能力と、表と突き合わせる作業は別物です。 前者は AI が得意で、後者は機械的な照合作業です。
なお、状態遷移の網羅基準として 0-switch(定義された全遷移を1回ずつ通す)は ISTQB FL にも出てきます。一方 1-switch(連続する2遷移の組合せ)は Foundation Level のシラバスには出てきません。Advanced 側の概念です。規格を引くときは、どのレベルの話かを分けておく必要があります。
DT:カバレッジ100%と25%が同時に成立する
決定表が一番はっきりした結果を出しました。同じ仕様書を3つの基準で測ると、こうなります。
全条件網羅(all_conditions) 100.0% ← 12/12
MC/DC 90.9% ← 10/11
全規則網羅(all_rules) 25.0% ← 18/72
同じ文書です。
意味はこうです。
- 全条件網羅:C1〜C4 の各条件が取りうる値が、それぞれ最低1回はどこかのテストに出てきたか → 全部出てきた
- 全規則網羅:条件の組合せ72通りのうち、何通りが検証されたか → 18通り
「カバレッジ100%です」と報告することも、「カバレッジ25%です」と報告することも、どちらも嘘ではありません。 どの基準で測ったかを言わない限り、カバレッジという言葉に意味がないということです。
ちなみに MC/DC は、DO-178B/DO-178C の Level A(航空機ソフトウェアの最高レベル)で要求され、ISO 26262 の ASIL D や IEC 61508-3 の SIL 4 でも推奨される基準です。そこそこ厳しい基準で 90.9% は出ています。 それでも全規則網羅では 25% です。
78件すべてが「条件を1つだけ動かした」テストだった
DT の指摘の中で、一番腑に落ちたのがこれです。
形式不正とサイズ超過が同時に発生する複合違反ケースが、78件のテスト中に1件も存在しない
78件すべてが、正常系から条件を1つだけ変えたテストでした。 形式だけ NG、サイズだけ NG、件数だけ NG。2つ同時に NG というテストがゼロです。
実運用で出るバグは、しばしばここに潜みます。「形式エラーとサイズエラーが同時に起きたとき、どちらのメッセージを出すか」は要件にも書かれていませんでした。テストがないので、要件の穴にも気づけません。
さらに、一般ロール × 非対応形式という組合せも完全に未検証でした。一般ロールで PNG を試すテスト(ロール起因の拒否)はあるのに、一般ロールで zip を試すテスト(形式起因の拒否)がありません。
Dedup:AI は冗長なテストを書かなかった
重複検出だけは良い結果でした。ユニーク率 99.9%。
見つかったのは3ペアだけで、しかも削除は非推奨という判定です。zip / exe / 拡張子なしの3件が「期待結果の文言が完全一致」しているだけで、別々の無効同値クラスなので残すべき、文言を差別化せよ、という指摘でした。
78件書いても冗長にならないのは、素直に AI の強みだと思います。
限界:監査する側も全数は見ていない
ここまで書いておいて何ですが、この監査ハーネスも完全ではありません。
重複検出のエージェントが、頼んでもいないのに自分から報告してきました。
N=78 の全 C(78,2)=3003 ペアを機械的に総当たり計算したものではなく、role / ファイル値 / 件数が重なる箇所を中心に系統的サンプリングした結果です
監査する側も、全数は見ていません。
これは正直な自己申告で、むしろこう出力されることが重要だと考えています。「監査しました、問題ありません」だけが返ってくる方が危ない。
限界を整理すると、こうなります。
| 何が達成できているか | 何が達成できていないか |
|---|---|
| コンテキストの分離、権限の制限、親の判断の遮断 | プロバイダ由来のバイアスの分離 |
| 規格に沿った機械的な数え上げ | 期待値そのものの妥当性判定 |
| 静的な突き合わせ(表とテストの対応など) | 実際に動かしての検証 |
| ISTQB §1.5.3 の2段目(some independence) | 3段目以上(チーム外・組織外) |
これは静的監査であって、テストの実行ではありません。 「テストケースが規格の観点で揃っているか」を見ているだけで、そのテストを実行したら通るのかは別の話です。
記事を書く前に、自分の実装のバグが3つ出た
最後に、この記事を書く過程で見つかったものを共有します。規格を引くときは、引用元まで戻って確認した方がいいという話です。
記事にする前に、参照している規格の記述を1つずつ原典で確認しました。その結果、自分たちのハーネス側に誤りが3つ見つかりました。
1. 境界値分析の定義が正反対だった。
ハーネスの内部ドキュメントには、こう書いてありました。
2-point method は invalid 境界(
min-1,max+1)を明示的に含まない設計を選択する
先ほど引いたとおり、ISTQB の 2-value BVA は「隣接パーティションに属する最も近い隣接値」、つまり invalid 側こそを含みます。 逆でした。
しかも同じドキュメントの説明文は「境界値そのものと境界を1だけ越えた値の組を取る」と正しく書いていて、その直後の結論だけが内側の値になっているという、内部矛盾を起こしていました。
デフォルト設定が6点すべてを見る方式だったため、今回の監査結果に影響はありませんでした。設定を変えていたら、規格を名乗りながら規格と逆のものを検査していたことになります。
2. 参照していた規格の節番号が違った。
「JSTQB FL §1.4.4 Independence of Testing」と書いていました。§1.4.4 は Traceability between the Test Basis and Testware です。 独立性は §1.5.3 です。節の名前は合っているのに、番号だけが違っていました。7ファイル11箇所に同じ誤りが伝播していました。
3. 論文の引用文が、その論文に存在しなかった。
内部ドキュメントには、先の arXiv 論文からの引用としてこう書かれていました。
"When the LLM under audit is also the LLM acting as oracle, the verification is structurally circular"
この英文はアブストラクトにありません。 論文が実際に報告しているのは「LLM は期待動作ではなく実際の動作を捉えるオラクルを生成する傾向がある」という内容で、関連はしますが同じことを言っていません。
書誌情報と実際の知見に差し替え、「主旨の要約であって逐語引用ではない」と明記しました。
加えて、IEEE 1012 の Independence Level を「Level 1〜4」の表として引用していた箇所も削除しました。規格本文が有料で、記述の裏付けが取れなかったためです。IEEE 1012 には Software Integrity Level 1〜4 という別概念が存在するので、混同していた可能性があります。
代わりに、無料で公開されていて誰でも確認できる ISTQB FL §1.5.3 の4段階を基準に置き換えました。根拠としてはむしろ強くなりました。
規格を引く仕組みを作ると、規格を引き間違えたときに、それが全部の出力に混ざります。 今回は記事にする前の確認で見つかりましたが、確認していなければ、監査結果に 2-point や存在しない引用が載ったまま配られていました。
まとめ
- AI が書いたテスト仕様書は、思ったよりよくできている。 78件、境界値・決定表・状態遷移表を自作し、要件の矛盾まで指摘してくる
- それでも規格で測ると 4技法平均 63.12%、最優先の欠落が6件出た
- 抜け方に型がある。 valid は書くが invalid が抜ける。上限は書くが下限が抜ける。要件に明示された側しか見ない
- 表は作るが、表と突き合わせない。 自分で「二重送信は不可」と書いて、それを試すテストを書いていなかった
- 条件を1つずつしか動かさない。 複合違反のテストが78件中ゼロだった
- カバレッジは基準で変わる。 同じ文書が全条件網羅で 100%、全規則網羅で 25%
- AI に AI をレビューさせても、独立性は ISTQB の2段目まで。 同一プロバイダ・同一 API キーではバイアスが共通する
- 循環を断つには、判断させず数えさせる。 効きそうに見える LLM Oracle を最初に外す
- 監査ハーネス自体も完全ではない。 全数を見ていないなら、そう出力させる
「AI にレビューさせているので大丈夫です」と言えるかどうかは、何を見せているかで決まります。 妥当性の判断を投げているなら、返ってくるのは同じバイアスの答えです。数えられるものだけを数えさせているなら、それは機械的な照合として機能します。
規格が価値を持つのは、「何を数えるか」を先に決めてくれている点だと思います。同値クラス、境界値、決定表の規則、状態遷移。これらは主観抜きで数えられます。 数えられるものを数えるところまでを自動化して、そこから先は人間が判断する。いまのところ、この線引きが現実的だと考えています。
参考
- ISTQB Certified Tester Foundation Level Syllabus v4.0.1(2024-09-15)— §1.5.3 Independence of Testing / §4.2 Black-box Test Techniques
- arXiv:2410.21136 — Konstantinou, M., Degiovanni, R., Papadakis, M. "Do LLMs generate test oracles that capture the actual or the expected program behaviour?" (2024-10-28)
- Modified condition/decision coverage - Wikipedia — MC/DC を要求する規格の一覧
- 検証環境: Windows 10 / Claude Code 2.1.239 / Claude Opus 5
※ 引用は原文と日本語訳を併記しています。訳は読みやすさを優先しているので、正確な表現は原典をご確認ください。
関連記事
- CLAUDE.md を厚くしても意味がなかった話 — 指示で守らせるのではなく、仕組みで縛るという話
- Claude Code の設定でハマる箇所まとめ — 同じく、確認しないと気づけない設定の話
JQITのエンジニアの95%以上は未経験からの採用です。
よければコーポレートサイトにも遊びに来てください。
エンジニア採用も行っています。もしご興味あれば覗いてみてください。
▶ 採用サイト