CONTENTS+
これまで私たちは、「正しいテストケースを作り、それを長く保守する」ことを前提にテスト自動化を組み立ててきました。もし必要なケースをその都度大量に生成できるなら、この前提自体が変わるのではないでしょうか。
テスト自動化は、アサーションの実行からブラウザ操作、実行環境、並列化、保守、テスト生成へと対象を広げてきました。一方で、その結果を「正しい」と判断するための基準は、別の問題として残ります。
生成できるテストケースの幅が広がり、判定 AI で意味上の正しさまで判定できるようになれば、1件ずつの期待値で合否を決めるだけでなく、多数のケースを生成し、複数のオラクルの判定結果の分布から品質を評価する方法も現実的になります。テスト自動化市場はその前提で動き始める、というのがこの記事の仮説です。
ツールごとに見るテスト自動化の対象
JUnit から生成 AI まで、自動化の対象は次のように広がってきました。
| 自動化された対象 | 代表例 | 機械側へ移ったもの | 残る仕事 |
|---|---|---|---|
| 判定の実行 | JUnit | アサーションの実行 | 期待値の定義 |
| ブラウザ操作 | Selenium | UI 操作 | シナリオ設計 |
| 実行工程 | Jenkins | ビルド・テスト・デプロイのオーケストレーション | 品質条件の定義 |
| 実行環境 | BrowserStack | ブラウザ・OS・端末・並列実行 | テスト内容と期待値 |
| 待機・分析 | Cypress | リトライ・フレーキーテストの検出・分析 | 失敗の意味 |
| 保守 | セルフヒーリング系 | ロケーター変更への追随 | 修復結果の妥当性 |
| 生成 | 生成 AI 系 | ケース・コード生成 | 何を検証するか |
ここで重要なのは、オラクル(実行結果が正しいかを判定する基準)がこれまで自動化されていなかった、ということではありません。JUnit の時点でオラクルの「実行」は自動化されています。一方で、actual == expectedのexpectedを何にするか、つまりオラクルの意味を定義する問題は別に残っています。
ツールが担う範囲は広がっても、テストケースを作り、オラクルと照らして PASS/FAIL を出すという形は変わっていません。
自動化しても残ったテストオラクル問題
テストオラクル問題は、生成 AI によって初めて生まれた問題ではありません。Barr らの2015年のサーベイは、ある入力に対して正しい挙動と誤った挙動を区別する問題をテストオラクル問題と整理し、オラクルの自動化がテスト自動化全体を広げるうえでのボトルネックだと指摘しています。
入力を自動生成できることと、その入力に対する結果が正しいと判定できることは別です。生成・実行・環境・保守へ自動化できる範囲が広がるほど、以前から残っていたテストオラクル問題は相対的に重要になります。
AI で変わるテストの各工程
生成 AI による変化は、テストコードの記述以外にも及びます。ケースの候補を作り、UI を操作し、変更に追随し、失敗を分析するといった複数の工程で、人間が1つずつ記述・確認していた作業を機械側へ移せるようになっています。
| 作業 | 従来の主な作業 | AI で起きている変化 |
|---|---|---|
| テスト設計 | ケースを考える | ケース候補の生成 |
| 実装 | テストコードを書く | コード生成 |
| UI 操作 | ロケーター・手順を記述 | 自然言語・エージェントによる操作 |
| 保守 | ロケーター変更へ追随 | セルフヒーリング |
| 分析 | 失敗の原因を調べる | 失敗の分類・要約 |
| 判定 | アサーションを実装 | 意味の判定も候補 |
もちろん、これらをすべて AI へ任せられるわけではありません。対象システムや実行環境によって適用できる範囲も異なります。それでも、ケースをその都度生成して試すことが現実的になる領域では、テストケースをどう持つかという前提も変わる可能性があります。
テストケースを保守する意味はどう変わるか
従来の自動テストでは、テストケースは長期間保守する資産として扱われることが多くあります。正しく設計し、名前を付け、仕様との対応を維持し、UI 変更に追随させます。
生成したケースを必要なときに実行できるなら、テストは「保存するテスト」と「生成する探索」に分けて考えられます。
| 保存するテスト | 生成する探索 |
|---|---|
| リグレッションテストのケース | 未知の挙動の探索 |
| 再現性 | 多様性 |
| 個々のケースの妥当性 | 集合としての探索能力 |
| 長期保守 | 必要時に再生成 |
この分け方には前例があります。
| 実践 | 生成するもの | 保存するもの | オラクル |
|---|---|---|---|
| プロパティベーステスト(QuickCheck、Hypothesis) | 実行のたびにランダムな入力 | 失敗した入力(次回の実行で再生) | 開発者が書いた性質(property) |
| ファジング(libFuzzer、OSS-Fuzz) | 変異させた入力 | カバレッジを広げた入力(コーパス)とクラッシュした入力 | クラッシュ・サニタイザーの検出 |
どちらも、探索のためのケースは生成し、失敗や有用な入力だけをリグレッションテストのケースとして残しています。OSS-Fuzz は2025年5月時点で、1,000のプロジェクトで13,000件以上の脆弱性と50,000件以上のバグの発見・修正を支援したとしています。
ただし、これらが成立したのは、オラクルを性質やクラッシュとして機械的に書ける範囲でした。生成 AI で変わるのは、この分け方を、意味上の正しさまで含む挙動に広げられるかどうかです。
生成したケースは毎回変わるため、失敗を再現できるかが問題になります。ここでも前例の仕組みが使えます。生成したケースと実行時の条件を記録しておき、失敗したケースは保存するテストに昇格させます。Hypothesis が失敗した入力を保存し、次回の実行で最初に再生するのと同じ考え方です。探索で見つかった失敗が、リグレッションテストのケースを増やしていきます。
既存のリグレッションテストは残ります。繰り返し保証したい挙動は、固定されたテストとして持ち続けます。一方で、入力や状態の組み合わせを広く試すためのケースは、その都度生成する方が適する領域が出てくると考えています。
そうなるとテスト設計の問いも、「どのケースを書くか」だけではなく、「どの入力空間・状態空間・利用文脈を、どの程度探索するか」へ広がります。
試す挙動が増えるほど、その結果をどう判定するかというオラクルの問題も大きくなります。
整理すると、テストの形は次のように変わります。以降の章では、AFTER の後半にあたる複数のオラクルと分布を見ていきます。
flowchart LR
A["テストケース"] --> B["オラクル"] --> C["PASS/FAIL"]flowchart LR
D["探索する範囲"] --> E["生成"] --> F["複数のオラクル"] --> G["分布"]オラクルとしての判定 AI
AI で変わる工程のうち、判定だけは性質が違います。テスト設計・実装・UI 操作・保守・分析はテストを作って動かす工程ですが、判定はその結果が正しいかを決める、オラクルそのものだからです。
mabl の GenAI Assertionsは、LLM-as-a-judge(LLM に出力の良し悪しを判定させる手法)を Web アプリケーションの状態評価に利用しています。TypeSafe AI が2026年に公開したJevも、与えられた状態に対して型付きの確率的な判定だけを返すことに特化しています。
ここで興味深いのは個々の製品よりも、「判定」が生成や操作とは別の AI ワークロードとして切り出され始めていることです。生成・実行できるテストの範囲が広がるほど、この判定をどのようなオラクルとして組み込むかが、テスト自動化の新しい設計領域になると見ています。
判定の件数が増えるほど、1件あたりのコストと速度が効いてきます。Jev を使った税務書類の分類の公開実装では、作者らが、以前の LLM ベースの分類器と比べてコストが約34分の1、速度が約6倍になったと報告しています。特定の実装の評価なので、テストの判定で同じ数字が出るわけではありません。ただ、判定を専用のモデルに切り出すと、大量のケースを判定する費用を下げられることは示されています。
1つの機能に含まれる3種類の正しさ
ただし、すべての正しさを判定 AI に任せればよいわけではありません。1つの機能の中にも、異なる種類の正しさがあります。機能の正しさを性質の違いから分けると、少なくとも次の3種類を考えられます。
| 正しさ | 例 | 期待値の出どころ | 向いているオラクル |
|---|---|---|---|
| 厳密な不変条件(Hard invariant) | 課金額、在庫、状態遷移 | 計算式・状態遷移の仕様 | 決定論的なアサーション |
| 規範的な制約(Normative constraint) | 認可、禁止操作、監査要件 | 権限表・ポリシー・規制 | 決定論的なアサーション(ポリシーから導いた許可・禁止) |
| 意味上の期待(Semantic expectation) | エラー理解、適切な遷移、意味的妥当性 | 利用者の目的 | 判定 AI による意味の判定 |
たとえば決済エラーという1つの機能にも、異なる正しさが含まれています。
- 課金されていないことは厳密な不変条件
- DB 状態が壊れていないことは厳密な不変条件
- 権限を越境していないことは規範的な制約
- エラー原因が伝わることは意味上の期待
- 修正後に次の行動が理解できることは意味上の期待
前半は決定論的なオラクルと相性がよいです。後半は、意図を満たす結果が1つに限りません。仕様で実装を1つに決め、期待値もそれに合わせて書くと、テストは意図ではなく実装の1つを確かめることになります。
たとえばセッション切れのあとに安全に再認証できることを保証したい場合を考えます。仕様が「ログイン画面へ遷移する」と定めていれば、URL == "/login"は仕様どおりの正しいテストです。ただ、その仕様自体が、意図を実装の1つに固定しています。ログイン画面への遷移、モーダルでの再認証、同一画面上での再認証のいずれでも目的を満たせるなら、本当に確認したいのは特定の URL ではなく「安全に再認証でき、作業を継続できること」です。
境界は「従来のテストか AI テストか」ではなく、その機能に含まれる正しさの種類にあります。認可のような規範的な制約も、ポリシーが決まっていれば決定論的に検査できます。不変条件と分けるのは、期待値の出どころが計算や仕様ではなく、権限表や規制だからです。1つの機能に、期待値の出どころが異なる複数のオラクルが共存する方が自然です。
オラクル自体もテストする
判定 AI もオラクルの1つです。ほかのテスト対象と同じように、その判定の精度を確かめる必要があります。
評価対象には、次のようなものがあります。
- 人間がラベルを付けたデータセットとの一致率
- 偽陽性
- 偽陰性
- 確信度のキャリブレーション
- モデル更新後のドリフト
- 判定が不確実なケースを人間へ回す閾値
LLM-as-a-judge の研究でも、人間との判定一致を測る一方、提示順による偏り(position bias)や冗長な回答を好む偏り(verbosity bias)などの問題が報告されています。「AI の判定だから信頼する」のではなく、対象タスクに対してオラクルそのものを継続的に評価・キャリブレーションする必要があります。
個々の判定を毎回人間が確認するのではなく、オラクル自体をテストし、不確実な判定を人間へ戻す。この構造なら、意味の判定を多数のテストに組み込む場合にも、人間による品質管理を別の層として残せます。
PASS/FAIL の一覧から結果の分布を見る
生成したケースによって広い範囲の挙動を探索できるなら、テスト結果の見方も個々の PASS/FAIL だけではなくなるかもしれません。
| 指標 | 観測するもの |
|---|---|
| 厳密な不変条件・規範的な制約 | 違反件数 |
| 通常フロー | 成功率 |
| エラーからの復帰 | 成功率 |
| 意味の判定 | スコア分布 |
| 不確実な判定 | 人間レビュー率 |
たとえば前述の決済エラーの機能で、1,000件のケースを生成して試した結果は、次のようにまとめられます。
| 正しさ | オラクル | 今回のバージョン | 前のバージョン |
|---|---|---|---|
| 課金されていない・DB が壊れていない | 決定論的なアサーション | 違反0 / 1,000件 | 違反0 / 1,000件 |
| 権限を越境していない | 決定論的なアサーション | 違反0 / 1,000件 | 違反0 / 1,000件 |
| エラー原因が伝わる | 判定 AI | 合格93%(95%信頼区間91〜95%) | 合格96% |
| 判定が不確実 | 判定 AI→人間 | 41件を人間レビューへ | 28件 |
この結果でリリースを止める理由になるのは、不変条件ではなく、意味の判定の合格率が前のバージョンを信頼区間の外まで下回ったことです。不合格の70件を個別の PASS/FAIL として眺めても、前のバージョンの40件から増えたことが偶然のばらつきなのかは分かりません。分布として見ると、エラーの伝え方が全体として悪くなった、という読み方ができます。
AI に「ユーザーの意図を達成できているか」を判定させると、テストが UX 評価に置き換わったように見えるかもしれません。ただ、ここで観測しているのは使い心地の良し悪しではなく、機能が目的を果たしたかどうかです。機能上の正しさのうち、意図を満たす結果が1つに限らない部分を、複数のオラクルと結果の分布から観測するという考え方です。
分布で品質を評価する考え方自体は、新しいものではありません。
| 実践 | 分布・統計で見ているもの |
|---|---|
| 運用プロファイル(Musa, 1993) | 利用頻度に応じたテストの配分 |
| Cleanroom の統計的使用テスト(Mills 他, 1987) | 利用確率の分布から生成したケースによる信頼性(MTTF)の認定 |
| 信頼度成長曲線 | バグ累積数の収束による出荷判定 |
| Kayentaのカナリア分析 | 新旧バージョンの指標分布の比較(Mann-Whitney U 検定) |
| pass@k | 生成した候補がテストを通る確率 |
特に Cleanroom の統計的使用テストは、利用の分布からケースを生成し、結果を統計的に評価するという点で、前述の図の AFTER とほぼ同じ形をしています。違うのは、判定できる正しさの範囲です。これまで統計的に扱えたのは、故障やバグの件数のように機械的に数えられるものでした。判定 AI によって、意味上の正しさまで分布の対象に入り始めています。
分布で評価するときの合否基準と限界
分布で評価するなら、合否の基準も2層に分かれます。
- 厳密な不変条件と規範的な制約は、違反0件と試行数をセットで示す
- 意味の判定は、割合と信頼区間で示し、前のバージョンの分布と比べる
違反0件だけでは、どれだけ安全かは分かりません。Rule of threeによれば、n 回試して違反が0件のとき、違反率の95%信頼区間の上限はおよそ3/n です。1万件生成して違反が0件でも、言えるのは「違反率は約0.03%未満」までです。
もう1つ問題になるのは、何の分布なのかです。生成するケースの偏りが実際の利用とずれていれば、得られるのは生成器の癖の分布です。運用プロファイルが利用頻度でテストを配分したように、生成の分布を利用の分布に寄せる設計が必要になります。
一方で、分布では評価できない領域もあります。まれで重大な欠陥は、分布の平均に埋もれます。私の QA の経験では、決済、認可、データ整合性、状態遷移のように1件の失敗も許されない領域は、分布ではなく決定論的にテストしなければなりません。分布による評価は決定論的なテストの代わりではなく、その外側に広がる挙動を観測する手段です。
実行基盤の次に厚くなる層
テスト実行基盤の上に、正しさを定義・観測するレイヤーが厚くなっていくと考えています。前述の図の段階ごとに、必要になるものを並べると次のようになります。
| 段階 | 必要になるもの |
|---|---|
| 探索する範囲 | 探索する範囲の設計、利用の分布との整合 |
| 生成 | 利用の分布に沿ったケース生成 |
| 複数のオラクル | 3種類の正しさに対応するオラクルの定義・実行、判定 AI の評価・キャリブレーション、不確実な判定の人間レビューへの振り分け |
| 分布 | 判定結果の集約、信頼区間を含むリリース基準の設定 |
この形は、LLM アプリの評価(evals)ではすでに製品になっています。
| 段階 | promptfoo | LangSmith | OpenAI Evals |
|---|---|---|---|
| 探索する範囲 | テストケースの集合 | データセット(手作業・本番の履歴) | データソース |
| 生成 | 評価対象のモデルで出力を生成 | 合成データでデータセットを作れる | 評価対象のモデルでデータセット全体の出力を生成 |
| 複数のオラクル | 決定論的なアサーションとモデルによる採点を重み付けで併用 | コードのルール、LLM-as-a-judge、人間の審査、ペアワイズ比較 | グレーダーによる採点 |
| 分布 | 加重スコアと閾値で合否 | 実験同士を比べてリグレッションを見る | 合格・不合格の件数を集計 |
LLM アプリは出力が毎回変わり、意図を満たす出力も1つに限りません。そのため、複数のオラクルと分布で評価する形が、通常のテストより先に製品になったと見ています。テストケースや操作を AI が生成するようになれば、通常のアプリケーションのテストにも同じ条件が生まれます。
これまでテスト自動化市場が実行基盤を厚くしてきたと見るなら、自動化できる範囲が広がった先で、正しさを定義・観測する基盤と呼べる領域に製品価値が集まる可能性があります。
このとき Jev のような判定 AI は、その一部を担う、意味を判定するオラクルの実装候補です。オラクルそのものを1つの AI に置き換えるのではなく、異なる種類の正しさに複数のオラクルを当て、それらを定義・実行・評価する仕組み全体が必要になります。
これまでのテスト自動化は、正しいテストケースを作り、長く保守することを前提に積み上げられてきました。ケースをその都度大量に生成できるなら、その前提は、探索する範囲を試し、複数のオラクルで判定し、分布で品質を評価する形へ移行すると考えています。
参考資料
- JUnit Cookbookjunit.org
- Selenium HistorySelenium
- Jenkins PipelinePipeline
- BrowserStack Automatebrowserstack.com
- abilityCypress Documentation
- Cypress Flaky Test ManagementCypress Documentation
- The Oracle Problem in Software Testing: A Surveydiscovery.ucl.ac.uk
- Three Years of Building Agents in Production (Part 1)mabl.com
- Introducing System One Models & Jevtypesafe.ai
- Judging LLM-as-a-Judge with MT-Bench and Chatbot ArenaarXiv.org
- Operational Profiles in Software-Reliability Engineeringdl.acm.org
- Cleanroom Software Engineeringtrace.tennessee.edu
- どこでテストをやめるのか?jasst.jp
- Automated Canary Analysis at Netflix with Kayentamedium.com
- Evaluating Large Language Models Trained on CodearXiv.org
- If Nothing Goes Wrong, Is Everything All Right?jhanley.biostat.mcgill.ca
- QuickCheck: A Lightweight Tool for Random Testing of Haskell Programscis.upenn.edu
- Hypothesis API Referencehypothesis.readthedocs.io
- libFuzzerllvm.org
- OSS-FuzzGitHub
- tax-doc-classifierGitHub
- Assertions & metricspromptfoo.dev
- LangSmith EvaluationDocs by LangChain
- OpenAI EvalsOpenAI Developers