AI時代のQA:システムが動くことを確認するだけでなく、壊し方を探そう
AIは、ソフトウェアの作り方を大きく変えています。これまで何時間、あるいは何日もかかっていた機能が、わずか数回のプロンプトで実装できるようになりました。
しかし、コードを書くスピードが上がる一方で、別の問題も生まれています。
コードが生成されるスピードに、チームによるテストと検証が追いつかなくなっているのです。
このような状況でも、QAの役割がなくなるわけではありません。むしろQAには、これまで以上に主体的かつ「対抗的」な姿勢が求められます。
単に、システムが想定されたシナリオどおりに動作するかを確認するだけではありません。
開発者が――人間であれAIであれ――想定していなかった状態へ、システムを意図的に追い込む。そして、どこで、どのように壊れるのかを探すことが重要になります。
AIはコードの何%を書いているのか?
この問いに対する答えは一つではありません。調査によって測定方法が異なるためです。
AIによって支援されたコードの割合を測定する調査もあれば、AIが完全に生成したコード、あるいは実際に本番環境へ投入されたAI生成コードだけを対象とする調査もあります。
Sonarが1,100人以上のプロフェッショナル開発者を対象に実施した「State of Code 2026」では、回答者は、AIが現在コミットされるコードの約42%に関与していると回答しています。この割合は、2027年には65%まで増加すると予測されています。
一方で、96%の開発者はAIが生成したコードを完全には信頼しておらず、AI生成コードをコミット前に常に検証していると回答した開発者は48%にとどまっています。
また、791人のプロフェッショナル開発者を対象としたFastlyの調査では、シニア開発者の32%が、自分たちがプロダクトに投入するコードの半分以上をAIが生成していると回答しています。
さらに、数百万人の開発者を対象とした分析では、実際に本番環境で使用されているAI生成コードの割合は、これより低い約26.9%と推定されています。
こうした数字の違いは、「AIによって支援されたコード(AI-assisted code)」と「AIが作成したコード(AI-authored code)」を区別する必要があることを示しています。
測定方法が何であれ、全体的なトレンドは明確です。
AIはソフトウェア開発プロセスに、ますます深く入り込んでいます。
そして、ここでより重要な問いが生まれます。
AIがますます多くのコードを書くようになったとき、AIが考えなかったケースを誰が見つけるのでしょうか?
AIは「目的」を解決するが、「現実世界のすべて」を解決するわけではない
AI Coding Agentには、通常、具体的な目的が与えられます。
- 画面を作る
- APIを追加する
- ファイルアップロード機能を実装する
- 決済機能を追加する
- Repository内のバグを修正する
- モジュールのテストを書く
AIは、これらのタスクを非常に速く完了できます。
しかし、「要求された機能を完成させること」と「実際のユーザーが取り得るすべての操作をカバーすること」は同じではありません。
AIが生成したフローが、次のように正常に動作するとします。
画面を開く → 正しいデータを入力する → Submitを1回クリックする → レスポンスを待つ → 成功通知を受け取る
これは**Happy Path(正常系)**です。
開発者が要件として記述する、理想的な利用シナリオです。
しかし、実際のユーザーはそうとは限りません。
- Submitを2回、3回と連続してクリックする
- Request処理中にページをRefreshする
- 同じレコードを複数のタブで開く
- ネットワークが切断された後にRequestを再送する
- 別のタブですでに削除されたデータを操作する
- 権限が変更された後も、その画面を使い続ける
- 最小値・最大値などの境界値を入力する
- 想定されていなかった順番で複数の機能を組み合わせて操作する
AI生成コードにおけるQA Coverageの問題を分析した事例でも、AIが生成した実装は一般的なシナリオに集中する一方、境界条件、ユーザー行動のバリエーション、Workflow上の例外などを見落としやすいことが指摘されています。
ここに、Happy Pathだけに集中する従来型のテストでは見落としやすい空白があります。
すべてのテストがGreenでも、プロダクトは失敗する
テストスイートがPassするのは、テストがまさに開発者が想定したシナリオを検証しているからかもしれません。
さらに、コードとテストの両方が同じ限定された仕様から生成されている場合、コードとテストが同じ問題を同時に見落とす可能性があります。
例えば、Delete機能が次の基本的なテストをPassしたとします。
レコードを開く → Deleteをクリック → Confirmする → レコードが消える
しかし、次のケースではどうでしょうか?
Deleteを同時に2回クリックする Tab Aで削除しながら、Tab Bで編集する レコードを削除した後、古いFormをSubmitする Request Timeout後にRetryする Background Jobの処理中に削除する
AI生成コードのテストに関するガイドでも、境界値、API Contract、Integration Errorに加えて、Duplicate Submit、Timeout、Invalid JSON、決済拒否などのAdversarial Inputを確認することが推奨されています。
つまり、「Test Pass」は、テストされたシナリオをシステムが通過したことを示すだけです。
それは、システムが現実世界のあらゆる使われ方に対して安全であることを証明するものではありません。
QAは「確認」から「対抗」へ
Edsger Dijkstraは、次のように述べています。
“Program testing can be used to show the presence of bugs, but never to show their absence!”
テストによってバグの存在を示すことはできます。
しかし、ソフトウェアにバグが存在しないことを証明することはできません。
AI時代において、この考え方はさらに重要になります。
AIによってコードを生成するスピードが上がったからといって、QAが同じようなテストを大量に追加すればよいわけではありません。
QAは、問いそのものを変える必要があります。
- 「このフローは正しく動くか?」だけではなく、
- 「このフローを失敗させるには、何をすればいいか?」
と考えるのです。
これが**Adversarial Testing(敵対的テスト)**の考え方です。
Adversarial Testingとは、無作為にテストしたり、目的なくシステムを壊したりすることではありません。
これは、QAが意図的に次のようなActorの立場になり、システムを体系的に検証するアプローチです。
- 待つことが嫌いなユーザー
- 操作を間違えるユーザー
- 複数のタブを開いているユーザー
- 同時に操作する複数のユーザー
- 不安定なネットワーク
- Requestが想定外の順番で完了する環境
- 意図的にシステムを異常状態へ追い込むActor
QAが考えるべき質問
それぞれの機能について、QAは次のような質問から始めるべきです。
- ユーザーがこの操作を繰り返したらどうなるか?
- 操作の途中で処理が中断されたらどうなるか?
- 2つのRequestが同時に実行されたらどうなるか?
- 2つのTabで状態が異なっていたらどうなるか?
- 他のユーザーによってデータが変更されたらどうなるか?
- Requestは成功したのに、UIが失敗だと認識したらどうなるか?
- UIは成功を表示しているのに、Backendでは失敗していたらどうなるか?
- 古いRequestが新しいRequestより後に完了したらどうなるか?
- Formを開いた後、Submitするまでの間に権限が変更されたらどうなるか?
- ユーザーがどのように操作しても、常に正しく維持されなければならない状態は何か?
これらの質問によって、QAは見落とされやすいリスクを検証できます。
- Duplicate Action
- Race Condition
- Stale State
- Multi-tab Conflict
- Out-of-order Response
- Network Failure
- Retry Behavior
- Input Boundary
- Authorization Change
- Cross-feature Interaction
- Data Integrity
- Partial Completion
シンプルな例
システムにファイルアップロード機能があるとします。
Happy Path
ファイルを選択 → Upload完了 → File IDをDatabaseに保存 → UIにファイルを表示
Adversarial Testingでは、これを次のように広げます。
同じファイルを2回Uploadする 2つのTabから同時にUploadする Upload中にRefreshする Upload中にModalを閉じる Upload完了前にFormをSubmitする Timeout後にRetryする Background Jobの処理中にファイルを削除する 拡張子は正しいがContent Typeが不正なファイルをUploadする
その後、QAは次のInvariantを確認します。
- StorageにOrphan Fileが残らない
- 存在しないファイルを指すDatabase Recordが作られない
- 意図しないDuplicate Recordが作られない
- Backendが失敗したにもかかわらず、UIがUpload成功を表示しない
- Retryによって意図しないSide Effectが発生しない
これが、
「Uploadが動くことを確認する」
ことと、
「Uploadがどのように失敗する可能性があるかを確認する」
ことの違いです。
AI生成コードからAdversarial Testingへ
AIはDeveloperがコードを書くスピードを大幅に向上させます。
しかし、コード生成のスピードが速くなったからといって、プロダクトのCoverageが保証されるわけではありません。
AIが特定の目的を達成するためにコードを生成するのであれば、QAはその目的の中に**「記述されていないもの」**を探す必要があります。
重要なテストアプローチには、次のようなものがあります。
繰り返し
- 素早く何度もClickする
- Formを連続してSubmitする
- Timeout後にRetryする
- Refresh後に同じ操作をもう一度行う
中断
- Networkを切断する
- Tabを閉じる
- 別ページへ移動する
- Request処理中にLogoutする
- 処理中に関連Entityを削除する
並行処理
- 2つのTabから同じデータを編集する
- 2人のUserが同じRecordを更新する
- 2つのDelete Requestを同時に実行する
- 新しいRequestが古いRequestより先に完了する
古い状態
- 以前開いたFormをSubmitする
- PermissionがRevokeされた後にデータを使用する
- 別の場所ですでに削除されたRecordを操作する
- 古いデータで新しいデータを上書きする
Feature間の相互作用
- UploadとForm Submitを組み合わせる
- Background Jobの実行中にデータを削除する
- 別の画面を開いている状態でPermissionを変更する
- Profileが参照しているファイルを削除する
QAの新しい役割
従来の開発プロセスでは、QAはDeveloperが機能を完成させた後にシステムを確認する「最後のチェック層」として捉えられることが多くありました。
しかし、AIを活用した開発プロセスでは、この考え方を変える必要があります。
AIはコード、テスト、ドキュメント、さらにはBug Fixの提案まで生成できます。
だからこそQAは、より多くの独立した思考を必要とする仕事に集中する必要があります。
- Implementationに存在するHidden Assumptionを特定する
- Requirementに記述されていないStateを見つける
- 複数のActorやSession間のInteractionを検証する
- Requestの並行実行によってのみ発生するBugを検出する
- InvariantとData Integrityを検証する
- Happy Path Testではカバーされない「攻撃」を設計する
QAは、単に次のように問いかける人ではありません。
「この機能は正しく動作しますか?」
これからのQAは、次のように問いかける人になります。
「このシステムは、どこで、どのような条件で失敗し、その結果どのような影響が発生するのか?」
結論
AIによって、ソフトウェアはこれまで以上に速く作れるようになっています。
しかし、コードが速く生成されることと、プロダクトがあらゆる現実世界の状況に対応できることは同じではありません。
現在の調査からも、AIがすでにコミットされるコードのかなりの割合に関与している一方、多くのDeveloperはAI生成コードを完全には信頼しておらず、プロダクトへ投入する前に検証する必要があることが分かります。
AI生成コードの多くは、Promptで指定されたHappy Pathや目的を達成することができます。
しかし、実際のユーザーはHappy Pathだけを進むわけではありません。
操作を繰り返します。
処理を途中で中断します。
同時に操作します。
古いデータを使用します。
そして、最初のRequirementには書かれていなかった方法で複数の機能を組み合わせます。
だからこそ、AI時代のQAは、
「システムが動作することを確認する」
だけではなく、
「システムを積極的に失敗させる方法を探す」
方向へ変わる必要があります。
単に、
「システムは動くか?」
と聞くのではなく、
「もしソースコードを変更せずにこのシステムを壊したいとしたら、次に何を試すだろうか?」
と問いかけるのです。
私は現在、Adversarial TestingとBug Huntingをより体系的に行うためのSkillセットを使っています。
もしこの記事に多くの反響があれば、私が実際に使用しているSkillセットの詳細も共有したいと思います。
参考資料
- State of Code Developer Survey report: The current reality of AI coding
- Senior developers let AI do more of the coding — survey
- More than 30% of code written in 2026 is generated by AI tools.
- AI-Generated Code Is Creating a QA Coverage Crisis in Enterprise SaaS