🧪

AI前提でE2Eテストを設計し直した話

に公開

アスエネ株式会社でエンジニアをしている田代です!

今回は、AIコーディングエージェントを前提にしたE2Eテストの設計について書きます。

はじめに

AIコーディングエージェントを使い始めてから、開発スピードは上がりました。
しかし、品質保証が開発スピードに追いついているかというとそうではない場合もあるかと思います。

この状況を変えるためにE2Eテストの整備を始めたのですが、単に「E2Eテストを書く」のではなく、AIに作成・更新を任せることを最初から前提にして設計しました。
この記事ではその設計、特にテストケースの管理方法と、人間とAIのレビューの分担について書きます。

前提として、私たちのプロダクトはフロントエンドとバックエンドが分離した構成のWebアプリケーションで、E2Eテストはゼロからのスタートでした。

クリティカルユーザージャーニーに絞らないという判断

E2Eテストのセオリーとして、テストケースはクリティカルユーザージャーニーに絞るべきという考え方があります。
これは、E2Eテストが単体テストや結合テストなどと比較して作成・保守コストが高いためです。
しかし、今回はE2Eテストのテストケースをクリティカルユーザージャーニーに限定せず、正常系を広くカバーする方針にしました。

理由は、AIによってテストの作成コストが下がったからです。
このセオリーはコストが高いことを前提にしたものなので、前提が崩れれば話も変わります。AIで作成・保守が回る仕組みを先に作り、その上で広く取りにいくことにしました。

とはいえ全部書くわけではなく、対象は正常系に絞っています。異常系まで含めるとケース数が膨大になるので、まずは主要な機能が正常に動くことの担保を優先しています。

E2Eテストで正常系を広くカバーする方針を採用した場合、よく採用されているテストピラミッドと比較すると、テストピラミッドよりもE2Eテストの範囲が増えるので、三角形よりも台形になるイメージです。

テストケースはGherkin構文で書いて、YAMLで管理する

今回の設計の中心はテストケースの管理方法です。テストケースはGherkin構文(Given / When / Then)で記述し、YAMLファイルで管理しています。

# test-cases/report-export.yaml
- id: TC-0012
  feature: レポート出力
  priority: high
  tags: [report, pdf]
  scenario: 管理者が年次レポートをPDF出力できる
  given:
    - 管理者としてログインしている
    - 2025年度の評価データが登録されている
  when:
    - レポート画面で「年次レポート」を選択する
    - PDF出力ボタンを押す
  then:
    - PDFファイルがダウンロードされる
    - レポートに評価スコアが表示されている

セレクタやAPIエンドポイントといったシステム側の言葉は出てきません。
自然言語なので、ユーザー目線のままレビューや管理ができます。

.featureファイルではなくYAMLにした理由

GherkinならCucumber系の.featureファイルが標準ですが、今回はYAMLを採用しています。
YAMLを採用したのは、IDやタグ、優先度といったメタデータをシナリオと同じ階層で構造的に持てることと、スキーマ検証がかけられることが理由です。

スキーマ検証がかけられることによって、AIエージェントが生成したテストケースに対して、IDの重複や必須フィールドの欠落を機械的に弾くことができます。
これにより、生成物を人間が目視で形式チェックする必要がなくなり、レビューの負荷を下げることができます。

テストケースIDとテストコードの紐付け

各テストケースのIDは、Playwrightのタグでテストコードと紐付けています。

test(
  '管理者が年次レポートをPDF出力できる',
  { tag: '@TC-0012' },
  async ({ page }) => {
    // ...
  },
);

テストケースIDとテストコードを紐付けることで、YAML側の一覧とコード側のタグを機械的に突合できます。
まだ実装されていないテストケースや、逆に対応するケースが消えたのに残っているテストコードを検出できます。

テストケースとテストコードが少しずつ乖離していって、気づいたらどちらも信用できなくなっている、というのはE2E運用のあるあるだと思います。
ここを人間の注意力に頼らず、IDの突合で機械的に防ぐようにしました。

--grep @TC-0012のように特定のテストを個別実行できるのも便利です。

レビューは人間が仕様を見て、AIがコードを見る

AIにテストを生成させると、生成されたものを誰がレビューするのかという問題が必ず出てきます。
全部人間が読むなら、AIで作成コストを下げた意味が半減します。

今回はテストケース(YAML)は人間が重点的にレビューし、テストコードはAIレビューをメインで人間は補助的に見る、という分担にしています。

テストケースの正しさは「仕様として正しいか」の問題なので、プロダクトの文脈を知っている人間にしか判断できません。
一方、テストコードの正しさは「テストケースに忠実に実装されているか」という照合作業なので、AIが得意とするところです。

自然言語でテストケースを管理することで、この分担がやりやすくなります。
人間がレビューすべき対象が、人間にとって一番読みやすい形式になっているからです。

並列実行まわりのデータ設計

広くカバーするとテスト数が増えるので、実行時間の問題が出てきます。並列実行で対応していますが、それを支えるデータ設計について簡単に触れておきます。

まず、システムを使う上で最低限必要になる基礎データを事前に用意してあり、各テストが毎回ゼロからデータを組み立てなくて済むようにしています。
その上で各テストはデータの作成から削除まで自己完結させて、実行前後で状態が変わらないようにしています。
これで並列実行しても互いに干渉しにくくなります。
それでも影響を受けやすいテストは、Playwrightのプロジェクトを分けて単独で実行できるようにしました。

テストデータの作成はSQLを直接叩くのではなくAPI経由にしています。
実際のユースケースに近い形でデータが作られますし、スキーマが変わってもAPIが吸収してくれるので保守が楽です。

この設計は社内のテックリードの方が推進されていた設計を参考にさせていただいてます!
(改めてこの場で感謝申し上げます!🙇‍♂️)

おわりに

E2Eテストの世界には長年のセオリーがいくつかありますが、その多くは「E2Eテストは作成・更新のコストが高い」という前提の上に成り立っています。
しかし、AIコーディングエージェントの登場によって、その前提は変わってきていると思います。

テストケースのYAML管理とID紐付け、正常系の広範囲カバー、並列実行の仕組みは実際に運用していますが、検討中の部分もあります。
今後は、AIコーディングエージェントによるテストケース・テストコードの定期的な自動更新を進める予定です。

AI前提のE2Eテストの設計について、同じような手詰まりを感じているチームがあれば、この設計が参考になればうれしいです。


最後になりますが、アスエネでは一緒に働くエンジニアを募集しています!
興味を持っていただけましたら、まずはお話しだけでもできればと思いますので、ご応募お待ちしております!

https://hrmos.co/pages/asuene/jobs?category=2020039468837949441

Discussion