はじめに
以前、私はE2E偏重について何度か記事を書きました。
当時から考え方は基本的に変わっていません。
E2Eは重要なテストレイヤーです。
しかし、
E2Eで確認できるのだから、E2Eで確認すればいい
という考え方には問題があります。
そして生成AIが急速に実用化され、Playwrightなどのテストコードを短時間で生成できるようになった現在、この問題はむしろ以前より重要になったと感じています。
最近は、こんな考え方も成立しやすくなりました。
AIがE2Eを書いてくれる
AIが壊れたE2Eを修正してくれる
なら、E2Eを大量に作っても問題ないのではないか
確かに、AIによってE2Eの作成コストは大幅に下がりました。
これは非常に大きな進歩です。
私自身、AIによるテストコード生成や分析には肯定的です。
しかし、
「AIによってE2Eを作るコストが下がった」
という事実と、
「だからE2E中心で品質を保証すればよい」
という結論は別の話です。
AIによって改善されたのは主に生成能力です。
どのリスクを、どのレイヤーで、どこまで保証するのか。
このテストアーキテクチャの問題は残っています。
この記事ではE2Eそのものを否定するのではなく、
AI時代だからこそ、なぜテストレイヤーの設計が以前より重要になるのか
を整理します。
AIが変えたのは「テストを書くコスト」
生成AIによって、テストコードを書く作業はかなり変わりました。
以前であれば、テストを作るには人間がかなりの部分を自分で進める必要がありました。
現在のCoding Agentでは、このかなりの部分をAIに支援させることができます。
これはE2Eに限りませんが、特にブラウザ操作を伴うテストでは効果が大きいでしょう。
しかし、ここで一つ分けて考える必要があります。
「テストコードを書くコスト」と「そのテストを持ち続けるコスト」は同じではありません。
E2Eの生成コストが下がっても、E2Eの特性は変わらない
例えばAIによって、100本のE2Eを非常に短時間で生成できたとします。
以前なら数週間必要だったものが、数時間で作れるかもしれません。
しかし、その100本は生成した瞬間に役割を終えるわけではありません。
その後も、
- CIで実行する
- テストデータを管理する
- UI変更に追従する
- 実行環境を維持する
- Flaky Testを調査する
- タイムアウトを調査する
- 外部サービスの変化に追従する
- Failureの原因を調査する
- 再実行する
必要があります。
AIはこれらの作業も支援できます。
しかし、
AIが対処できる
ことと、
そのコストや複雑性が存在しなくなる
ことは同じではありません。
例えば、
| 項目 | AIによる改善 |
|---|---|
| テストコード生成 | 大きく改善 |
| テストコード修正 | 大きく改善 |
| Failure解析 | 改善 |
| テストデータ生成 | 改善 |
| 実行時間 | 根本的には残る |
| ブラウザ依存 | 残る |
| ネットワーク依存 | 残る |
| 外部サービス依存 | 残る |
| 環境依存 | 残る |
| CIリソース消費 | 残る |
| Failure Signalの信頼性 | 設計次第 |
| テストレイヤーの選択 | 設計判断が必要 |
AIはE2Eを扱いやすくすることはできます。
しかし、E2EをUnit TestやIntegration Testと同じ性質のものに変えるわけではありません。
「作るコスト」と「持ち続けるコスト」
ソフトウェアでは、初期開発コストだけを見てアーキテクチャを決めることはありません。
運用、保守、変更容易性、インフラコストなども考えます。
テストも同じです。
AI以前には、E2Eの作成コストそのものが一定のブレーキとして働いていました。
AIによって、その制約はかなり小さくなります。
ここまでは問題ありません。
問題は、その先です。
生成コストが下がった結果、テストスイート全体の運用コストが増える可能性があります。
言い換えれば、
AIはテストのCAPEXを大幅に下げましたが、OPEXをゼロにはしていません。
むしろ生成量が増えれば、総OPEXが増加する可能性があります。
E2Eでテストできることと、E2Eでテストすべきことは違う
ここが最も重要です。
例えば次の仕様を考えます。
- 特定の入力ならエラーになる
- 特定権限では処理できない
- APIが特定条件で400を返す
- DB更新後にstatusがcompletedになる
- Queueに正しいJobが投入される
- Retryしても二重処理されない
これらは、頑張ればすべてE2Eで確認できます。
ブラウザからシステム全体を通せば確認できるでしょう。
しかし、
E2Eで確認可能であることは、E2Eで確認するのが最適であることを意味しません。
例えば、
Retryしても二重処理されないこと
を確認したいとします。
この仕様の本質が、
- DBのAtomicな状態更新
- Queueの重複防止
- Workerの冪等性
なのであれば、ブラウザからシステム全体を動かす必要が本当にあるでしょうか。
実DBや実Queueを使ったIntegration Testで、必要な境界だけを動かすこともできます。
こちらの方が、
- 高速
- 再現性が高い
- 状態を作りやすい
- Failureを局所化しやすい
- 異常系を作りやすい
のであれば、そちらで保証した方が合理的です。
テストケースからテストレイヤーを決めない
E2E偏重が起きる理由の一つに、
テストケースの文章からテストレイヤーを決めてしまう
ことがあると思っています。
例えば、
ユーザーが商品を選択する
購入ボタンを押す
金額が表示される
というシナリオがある。
UI操作が書かれているため、
これはE2Eで自動化しよう
となります。
しかし、本当に確認したかったリスクが、
金額計算ロジックが正しいこと
なら、Unit Testの方が適しているかもしれません。
本当に確認したかったことが、
APIから受け取った価格とDB上の商品情報が正しく処理されること
なら、Integration Testかもしれません。
もちろん、
ユーザーが実際に商品を購入完了できること
を保証したいのであれば、E2Eが適しています。
つまり重要なのは、
「どう操作するか」ではなく、「何が壊れることを恐れているのか」
です。
RiskからTest Layerを決める
私は、テスト設計を次の順序で考える方が合理的だと思っています。
例えば、
一方、テストケースから始めると、こうなりやすい。
この流れでは、
テストケースの表現方法によってテストレイヤーが決まってしまいます。
これは順序が逆です。
Testing TrophyはAI時代でも崩れない
私はTesting Trophyに近い考え方を採っています。
ただし、重要なのは単純にテスト本数をトロフィーの形にすることではありません。
この記事での考え方を構造として表すと、次のようになります。
それぞれのレイヤーには異なる責務があります。
Static
- 型
- Lint
- 構文
- 静的に検出できる契約違反
Unit
- 純粋なロジック
- 条件分岐
- 境界値
- 小さな振る舞い
Integration
- DB
- Queue
- API
- Repository
- Worker
- Service間連携
- 外部I/Oとの境界
E2E
- システム全体の接続
- 本番に近い環境での成立性
- ユーザーにとって重要な導線
重要なのは、
UnitとE2Eのどちらが優れているか
でも、
Integration Testを何本書くべきか
でもありません。
検出したいFailure Modeに対して、最も適切なレイヤーを選択することです。
AIがコードを書くようになっても、この原則は変わりません。
E2EにはE2Eでしか得られない価値がある
ここまで読むとE2E否定論に見えるかもしれません。
しかし、E2Eは非常に重要です。
例えばECサービスなら、次のようなクリティカルなユーザージャーニーがあります。
各APIが正常。
DBも正常。
決済Serviceも正常。
Frontendも正常。
それでも、
すべてを接続した結果としてユーザーが購入できる保証にはなりません。
ここはE2Eに大きな価値があります。
つまり、
E2Eを減らすこと自体を目的にしてはいけません。
必要なら増やせばいい。
問題なのは、
E2Eでなくても十分に保証できるFailure ModeまでE2Eに押し込むこと
です。
「AIがFlaky Testを直してくれる」なら問題ないのか
これもよく考える必要があります。
AIはFlaky Testの解析にも利用できます。
例えば、次のような作業を自動化できます。
この作業をAIが高速化する。
これは非常に有効です。
しかし、品質保証として見ると別の問題があります。
そのFailure Signalを信用できるか
という問題です。
仮に1000本のE2Eがあり、毎日のように何本か失敗するとします。
そして、その多くが、
- Timing
- Network
- Test Data
- Browser
- Environment
- External Service
などに起因している。
AIが毎回修復してくれたとしても、CIを見る人間には次第に、
またE2E側だろう
という認識が生まれます。
ここが危険です。
本当のRegressionとテストインフラ由来のFailureが、同じ「赤」として表示されるからです。
テストの価値は、
何本あるか
だけではありません。
Failure Signalをどれだけ信用できるか
も重要です。
AIによって修復コストが下がっても、この問題はなくなりません。
AIはテスト負債も高速に生成できる
生成AIは非常に強力です。
コードを高速に生成できます。
テストも高速に生成できます。
しかし当然、
設計が間違っていれば、不要なコードも高速に生成できます。
これはテストでも同じです。
生成能力だけが急激に上がり、設計判断が変わらなければ、
不要なテストも以前より高速に増やせます。
AI以前には、
書くのが大変だから、本当に必要なテストを選ぶ
という物理的な制約がありました。
その制約がなくなりつつあります。
だからこそ、
「何を書くか」以上に「何を書かないか」を判断する能力
が重要になります。
「なぜこのテストはE2Eなのか?」に答えられるか
E2Eを追加するとき、私は次の質問が有効だと考えています。
このテストで検出したいRisk / Failure Modeは何か?
次に、
そのFailure ModeはIntegration Testでは検出できないか?
さらに、
Unit Testでは検出できないか?
Static Analysisでは検出できないか?
と、より高速で安定したレイヤーへ降ろせないか考えます。
判断の流れを図にすると、こうなります。
それでも、
システム全体を接続しなければ検出できない
のであれば、E2Eに置く合理的な理由があります。
この判断に、
AIなら簡単に作れるから
という理由は本来関係ありません。
テストコードの生成コストではなく、
Failure Detectionに必要な境界
からTest Layerを決めるべきだからです。
EM・テックリードにとって、これは「テストだけの問題」ではない
E2Eの構成は、テストチームだけの問題ではありません。
テストレイヤーの設計は、
- CI時間
- PRのFeedback Loop
- Lead Time
- Flaky率
- 障害調査時間
- テスト環境維持コスト
- Infrastructure Cost
- Developer Experience
に直接影響します。
例えばE2Eを100本から500本に増やしたとします。
そのとき見るべきなのは、
テストケースが400本増えた
という数字だけではありません。
見るべきなのは、
- Regression Detectionは改善したか
- CI時間はどうなったか
- Failure Signalの信頼性はどうなったか
- PRのFeedback Loopはどうなったか
- 保守工数はどうなったか
- 環境維持コストはどうなったか
です。
テストケース数が増えていても、
CIが遅くなり、
Failureが信用されなくなり、
開発者がテスト結果を待ち、
頻繁に再実行するようになっているのであれば、
それを単純に、
品質保証が強化された
とは評価できません。
これはQAだけの問題ではなく、
Engineering ProductivityとSoftware Architectureの問題
です。
だからこそ、EMやテックリードもテストアーキテクチャに関与する必要があります。
AI時代に価値が上がるのは「生成」ではなく「選択」
AIによって、
テストコードを書く能力そのものの希少性は下がっていく
と思います。
Playwrightを書く。
Unit Testを書く。
Mockを作る。
Test Dataを作る。
こうした作業の多くをAIが支援してくれるでしょう。
一方で、
- 何をRiskとするのか
- 何を保証するのか
- 何を保証しないのか
- どのFailure Modeを検出するのか
- どのTest Layerを使うのか
- どのテストをCI Blockingにするのか
- どのユーザージャーニーだけE2Eにするのか
という判断は、むしろ重要になります。
なぜなら、
作ることが簡単になったからです。
AI時代だからこそ、テスト戦略が重要になる
AIによってテストコードを書くことは、これからさらに簡単になるでしょう。
だから私は、
AIがテストを書いてくれるから、テスト戦略は簡単になる
とは考えていません。
むしろ逆です。
生成コストが下がるほど、選択と設計が重要になります。
E2EをAIに100本生成させる前に、
と考える。
そして、
決めたレイヤーのテスト実装をAIに任せる。
この順序が重要だと思っています。
まとめ
AIによってE2Eテストの生成コストは大幅に下がりました。
これは間違いなく大きな進歩です。
しかし、
AIがE2Eを書ける
ことと、
E2E中心のテスト戦略が合理的である
ことは別問題です。
AIは、
「How to write」を大幅に効率化しました。
だからこそ人間は、
「What to test」
「Why to test」
「Where to test」
を、これまで以上に考える必要があります。
私はE2Eを減らすこと自体を目的にはしていません。
Unit Testを増やすことも、Integration Testを増やすことも目的ではありません。
目指すべきなのは、
Riskに対して、最も適切なTest Layerで、必要十分な保証を作ること
です。
そして、その設計が終わった後でAIを使えばいい。
AIは非常に優秀な実装者になりつつあります。
しかし、優秀な実装者に、
何を大量生産させるのか。
そこを間違えれば、AIは品質基盤だけでなく、テスト負債も高速に作ることができます。
だからこそ私は、
AI時代になった今の方が、以前よりテスト戦略が重要になった
と考えています。
