はじめに
過去に、一つのプロダクトで自動テストを書く期間を一定期間設けてテストを書ききった事があるのですが、いざ機能追加や画面追加・改修のフェーズになった時、自動テストを運用しきるのって負荷高くて辛いなぁと感じた事があります。
まわりを見ていても、継続的にちゃんと運用しきれているケースは少ないと感じます。
色んな問題があるとは思いますが特に課題としては、
- E2Eテストを書き直すコストが大きい
これにつきると考えています。
その原因としては、
- E2Eテストを片っ端から書いた事(例:文言が正常であること、失敗のケースも漏れなくテストする等)
- E2Eテストで重視すべきテストシナリオの洗い出しができていなかったこと(コストと品質のバランス)
が一因としてあるなと感じております。
本当に 網羅性のみの観点でE2Eテストを書きまくってしまう と、エンジニアが辛い思いをする(過去の自分がそうだった)ので、なんとか戦略を練りたいところです。
では、コストと品質のバランス を取るためにどうしたら良いのか?
少し考えてみることにしました。
1. 各社のテスト戦略
まずは著名なWebサービス(Google, Netflix, Meta, Spotifyなど)がどのように自動テストを書き、運用しているのかを知った上で自社プロダクトに目を向け、その上で自社ならどうなのか?を考えていく必要があると感じております。
※これらの企業が使用している解決方法は、彼らが抱える膨大なユーザーやトラフィックに対するものであり、必ずしも万人に適用できるものではないです。しかし参考にできる部分はあります。
さて、調査してみると、それぞれの企業が抱える課題(規模、サービスの性質)によって、採用している戦略が異なることがわかりました。
Google:堅実な「テストのピラミッド」と文化
Googleは、巨大なモノレポ(単一のコードリポジトリ)を扱うため、テストの実行速度と安定性を最優先しています。
- 70/20/10の法則:
- 70% Unit Test: 小さく、高速。関数単位
- 20% Integration Test: 複数のモジュール間の結合
- 10% E2E (End-to-End) Test: ユーザーシナリオに基づくUIテスト
- 理由: E2Eは壊れやすく遅いため、土台(Unit)を厚くしてフィードバックを早くする戦略です
- Hermetic Servers (密閉されたサーバー):
- テストが外部(実際のDBやAPI)に依存して不安定にならないよう、テスト環境を完全に隔離・模倣する技術を徹底しています
Googleのテスト戦略(Unit重視、E2Eはコストが高いので減らす)に関するソースです。
- 【書籍】Googleのソフトウェアエンジニアリング (O'Reilly)
- Web版 (英語・無料): Software Engineering at Google (Online)
※Google自身がWebで無料公開しています。リンク先はChapter 11 (Testing Overview) です。
- 【ブログ】Google Testing Blog: "Just Say No to More End-to-End Tests"
- 「E2Eテストを増やしすぎるな(Noと言おう)」という、テストピラミッドの重要性を説いた有名な記事です。
Netflix:本番環境こそがテスト環境
Netflixはマイクロサービスアーキテクチャの先駆者であり、結合部分が複雑すぎて完全にローカルで再現するのは不可能。そのため、「本番での耐性」を重視する方針としています。
- Chaos Engineering (カオスエンジニアリング):
- 有名なツール「Chaos Monkey」を使い、本番稼働中のサーバーをランダムに落とします。それでもサービスが停止しないよう、自己修復能力を日常的にテストしています。
※「本番環境でテストする(Chaos Engineering)」という過激な手法は、彼らの技術ブログで詳細に公開されています。
【ブログ】Netflix TechBlog: "The Netflix Simian Army"
サーバーをランダムに障害状態にする「Chaos Monkey」を含むツール群「Simian Army」の発表記事です。
- Canary Analysis (カナリアリリース):
- 新しいコードを全ユーザーにいきなり公開せず、一部のユーザーにのみ公開。エラー率やパフォーマンスを自動計測し、問題があれば自動でロールバックします
記事: "Automated Canary Analysis at Netflix with Kayenta" (2018)
※カナリアリリース(一部ユーザーにだけ新機能を出す)の自動化プラットフォーム「Kayenta」についての技術解説です。
Meta (Facebook):開発者体験(DX)への執着
Metaは「Move fast(速く動く)」を掲げているため、テストを書く負担を減らすことに注力しています。なので、「開発者体験(DX)」と「CIの高速化」に関する発表が多いです。
- Snapshot Testing (Jest):
- UIコンポーネントの出力結果(HTML構造など)を「写真(スナップショット)」のように保存し、前回との差分だけを検知します。「テストコードを書く」のではなく「差分を確認する」スタイルを広めました。
【ドキュメント】Jest: Snapshot Testing
Metaが開発したテストフレームワークJestの公式ドキュメント。「コンポーネントのUIが予期せず変更されていないか」を確認する手法について書かれています。
- Sandcastle (CI):
- モバイルアプリのテストはデバイスが必要で時間がかかりますが、彼らは数千台のスマホ実機をデータセンターに並べ、並列で高速にテストを実行するインフラを自作しています。
Conference: @Scale / F8
発表: "Rapid Release at Massive Scale"
数万人のエンジニアが働く中で、どのようにマージキューを管理し、モバイル実機ファーム(Sandcastle/One World)で並列テストを行っているかが語られています。Meta Engineeringのブログでも "Continuous Deployment" 関連の記事で確認できます。
Spotify:ピラミッドではなく「蜂の巣」
Spotifyはマイクロサービスが多いため、Unitテスト(単体)だけでは不十分と考え、Integration Test(結合テスト) を最重要視しています。
- Testing Honeycomb:
- Unitテスト(詳細すぎる)やE2E(遅すぎる)よりも、API等の「結合テスト」を一番厚くする戦略を採用しています
- 「実装の詳細」ではなく「振る舞い」をテストすることで、リファクタリングへの耐性を高めています
【ブログ】Spotify Engineering: "Testing of Microservices"
この記事で「Testing Honeycomb(蜂の巣型のテスト戦略)」の図解が登場しました。「実装の詳細(Unit)よりも、振る舞い(Integration)をテストせよ」と説いています。
2.各社のテスト戦略まとめ
- Google:ピラミッド(Unit重視、E2Eはコストが高いので減らす)
- Netflix:本番環境こそがテスト環境(カオスエンジニアリング。本番サーバーをわざと落とす)
- Meta (Facebook):スナップショットテストによるUIの差分検知(速く動くを重視。テストを書く負担を減らす)
- Spotify:テスティング・ハニカム(統合テスト重視)
3. 各社の共通点
各社、運用・オペレーションの共通ルールツールは違えど、運用の仕組みには共通点があります。
① Flaky Test(結果が不安定なテスト)の撲滅
- 「たまに落ちるけど、再実行したら通るテスト(Flaky Test)」は、開発者の信頼を損なうため、ウイルスのように扱われます
- Quarantine (隔離):
- 不安定なテストが見つかったら、即座にメインのCIパイプラインから除外(隔離)されます
- 修正されるまでテストとしてカウントしません。「常にGreen(成功)」か「常にRed(失敗)」である必要があります
- 再実行(Retry)は最終手段:
- 安易なリトライ設定はバグを見逃す原因になるため、根本原因(非同期処理のミスやテストデータの汚れ)の修正が推奨されます
② Merge Queue (マージキュー)
GitHubなどのPull Requestが増えると、「最新のmainブランチの状態」と「自分のブランチ」の整合性が取れなくなります。
- 運用の仕組み: * マージボタンを押してもすぐにはマージされず、「マージ待ち行列(Queue)」に入ります。システムが仮想的にマージした状態でテストを走りらせ、パスしたものだけを順番に本番ブランチへ取り込みます。UberやShopifyなどで導入されています
4. 傾向と分析
「リポジトリの構成(モノレポかマイクロサービスか)」によって、「どこが一番壊れやすいか(リスクの所在)」 が変わるため、重視すべきテストの種類も必然的に変わります。
その理由をAIと壁打ちして分析してみました。
1. モノレポ構成(Google型)が「Unit重視」になる理由
Googleのような巨大なモノレポでは、一つの共通ライブラリ(例:日付処理)を数千のプロジェクトが参照しています。
- リスクの所在: 「共通部分の変更が、意図せず全く別のプロジェクトを破壊すること」
- なぜUnitなのか:
- ビルド時間の問題: 全プロジェクトの結合テストを走らせると、完了まで何日もかかってしまいます
- 影響範囲の特定: 「この関数が正しい値を返すか」という最小単位(Unit)で保証しないと、影響範囲が広すぎてデバッグ不能になります
- 結論: モノレポでは、全体の整合性よりも 「個々の部品が仕様通りであること(Unit)」 を高速に保証しないと、開発が止まってしまいます
2. マイクロサービス構成(Netflix/Spotify型)が「統合重視」になる理由
機能ごとにサーバー(サービス)が分かれており、HTTP通信やメッセージキューで会話します。
-
リスクの所在: 「サービスAとサービスBの通信(つなぎ目)」
-
サービスA「データを送ったよ」→ サービスB「形式が違うからエラーだわ」という事故が多発します
-
なぜ統合(Integration)なのか:
- 個々のサービス内でUnitテストが完璧でも、通信相手の仕様が変わっていたらシステムは動きません
- そのため、「実際にAPIを叩いてレスポンスが返ってくるか」を確認する結合・統合テスト(Testing Honeycomb)が最重要になります
-
結論: マイクロサービスでは、部品の品質よりも 「部品同士のつながり(Integration)」 を保証しないと、システム全体として動きません
5. 各社共通点
ここから、各社共通して言えることは以下だとわかります。
- E2Eテストを増やしすぎない。メンテコストが膨れ上がらないようにする
- 運用不安定なテストは即隔離
- 「たまに落ちる」テストは入れない方がマシ。CIの信頼性を守る
6.E2Eテストの指針
では、E2Eテストはどの観点で書けば良いのでしょうか?
E2Eテスト(End-to-End Test)におけるテスト観点について、業界全体で統一された「唯一の公式規格(ISOなど)」のようなものは存在しませんが、GoogleやCypress、Playwrightなどの主要プレイヤーや、ソフトウェアテストの権威(Martin FowlerやKent C. Doddsなど)が提唱する 「デファクトスタンダード(事実上の標準)」となるガイドライン は存在します。
これらに共通する 「E2Eテストで何をテストすべきか」 という主要な指針を整理してまとめました。
1. 基本原則:E2Eテストの役割
E2Eテストは「実行コストが高く、壊れやすい(Flaky)」という特性があります。そのため、 「すべてを網羅しようとしない」 ことが最大のガイドラインです。
-
テストピラミッド/テスティングトロフィー: E2Eテストはピラミッドの頂点(最小限)に位置づけるべきです
-
目的: 「ユーザーがアプリケーションを使って主要な目的を達成できるか」を確認することです
2. E2Eテストの具体的なテスト観点
ガイドラインとして推奨される主な観点は以下の通りです。
① クリティカル・ユーザー・ジャーニー (Critical User Journey)
ユーザーにとって「これができなければサービスとして成り立たない」という最も重要な動線をテストします。
- ハッピーパス(Happy Path): ユーザーが迷わず操作し、エラーなく完了する成功ルート
例:ログイン → 商品検索 → カート投入 → 決済完了 → サンクスページ表示 - ビジネス価値の高い機能: 売上に直結する機能や、コアとなる価値提供機能
② システム間の連携 (Integration)
単体テストでは確認できない、コンポーネントやシステム間の繋ぎ目を検証します。
- DBへの保存と読み出し: フロントエンドの入力が正しくDBに保存され、再取得できるか
- 外部API連携: 決済ゲートウェイ、認証プロバイダ(Auth0など)、メール配信システムなどとの連携が機能しているか
③ ユーザーからの「見え方」と「操作性」
コード内部の論理値ではなく、実際のDOM(画面)の状態を検証します。
- 可視性 (Visibility): ボタンが他の要素に隠れていないか、クリック可能か
- 状態変化: ローディングスピナーが表示され、処理完了後に消えるか
- 画面遷移: リンクをクリックした後、正しいURLやページタイトルに遷移するか
④ 致命的なエラーハンドリング
「入力ミス」などの細かいバリデーションは単体テストで行いますが、「システム上の不整合」や「重要な拒否」はE2Eで確認します。
- 認証エラー: ログインしていないユーザーが保護されたページにアクセスした場合、ログイン画面にリダイレクトされるか
- クリティカルな失敗: 決済失敗時に適切なメッセージが出るか(画面がフリーズしないか)
3. E2Eテストに「含めるべきではない」観点(アンチパターン)
多くのガイドライン(特にCypressやGoogle Testing Blog)では、以下をE2Eでテストすることを避けるべきとしています。
- 細かい境界値分析・入力バリデーション:
- × 「メールアドレスの@がない場合」「パスワードが7文字の場合」などの全パターン
- ○ これらは単体テスト(Unit Test)でカバーすべきです
- 見た目の細かいデザイン(ピクセル単位):
- × 「ボタンの色コードが#FFFFFFか」「マージンが10pxか」
- ○ これらはVisual Regression Test(画像回帰テスト)の領域です
- 外部サイトの動作保証:
- × TwitterやFacebookのログイン画面自体の挙動テスト
- ○ 自社アプリから外部へ遷移できるか、戻ってこれるかのみを確認します
4. 参考となる主要ガイドライン・資料
チーム内で基準を作る場合は、以下のドキュメントなどを参考にするのが良さそうです。
- Cypress Best Practices: 近年のE2Eのスタンダード。「テストを独立させる」「DOMのセレクタの選び方」「不要な待機時間を避ける」など具体的
- Playwright Best Practices: 「ユーザーに見えるものをテストする(Test user-visible behavior)」という哲学に基づいたロケータ戦略などを解説
- The Testing Trophy: Kent C. Dodds提唱。「E2Eは少なめに、結合テスト(Integration)を厚く」という現代的なWeb開発の指針
- Google Testing Blog: "Just Say No to More End-to-End Tests" という記事で、E2Eの信頼性と速度のバランスについて論じています
6. E2Eテストはクリティカル・ユーザー・ジャーニーを保証しよう
E2Eテストの観点を一言で言えば、「ユーザー視点(目的が達成できるか)で、主要な成功ルート(クリティカル・ユーザー・ジャーニー)を保証する」 ことに尽きます。
参考に、一般的な来店予約管理システムの場合のクリティカル・ユーザー・ジャーニーをAIと壁打ちして出してもらいました。
推奨する3つの主要テストシナリオ
1. 新規予約の完了(ハッピーパス)
これが動かないとサービスの意味がない、最も基本的な「成功ルート」です。
- シナリオのゴール: ユーザーが希望の日時・コースを選び、予約を確定できること
- 具体的なステップ:
- 1.トップページ(または店舗ページ)を開く
- 2.カレンダーから「空いている日時」を選択する
- 3.(もしあれば)メニューやコースを選択する
- 4.ユーザー情報(名前・電話番号など)を入力する
- 5.「予約確定」ボタンを押す
- 検証ポイント(アサーション):
- 画面: 「予約完了画面(サンクスページ)」が表示されるか?
- データ: 予約IDが発行されているか?(画面上に表示、またはマイページに反映)
2. 予約の確認とキャンセル
ユーザーが自分の予約を確認し、取り消しができるかを確認します。ここがバグると「ユーザーが店に来ない(No Show)」や「ダブルブッキング」の原因になります。
- シナリオのゴール: 既存の予約を正しく参照でき、キャンセル処理が反映されること
- 具体的なステップ:
- 1.マイページ(または予約確認URL)にアクセスする
- 2.先ほど作成した予約の詳細を開く
- 3.「キャンセルする」ボタンを押す
- 4.確認ダイアログで「はい」を選択する
- 検証ポイント(アサーション):
- 表示: ステータスが「キャンセル済み」に変わっているか?
- 再確認: もう一度カレンダーを見た時、その枠が「空き(予約可能)」に戻っているか?
3. 排他制御・バリデーション(満席時の挙動)
単純な入力ミスではなく、「ビジネスロジック上のガード」が効いているかを確認します。
- シナリオのゴール: 満席の枠や、過去の日時など「予約できない条件」で適切にブロックされること
- 具体的なステップ:
- 1.カレンダー画面を開く
- 2.「既に満席の枠(×印)」または「休業日」 をクリックする
- 3.(あるいは)強制的にURL等で予約フォームに進もうとする
- 検証ポイント(アサーション):
- UI: そもそもクリックできない(Disabled)状態になっているか?
- エラー: 無理に進めた場合、「選択された日時は予約できません」といった適切なエラーメッセージが表示され、完了画面に行かないか?
もし余裕があれば検討したいE2E
上記の3つは「一般ユーザー側の画面」だけで完結するものですが、予約システムのE2Eとして最も価値が高いのは、「ユーザーと店舗の連携」 を一気通貫で見ることです。
- ユーザー × 店舗管理者 の連携テスト
- 1.(ユーザー画面で)ユーザーが12:00に予約を入れる
- 2.(管理者画面で)店舗スタッフとしてログインする
- 3.(管理者画面で)予約台帳を開くと、12:00にそのユーザーの名前が表示されているか確認する
結論
調査の結果より、自動テスト(主にE2E)を運用していくためには以下を意識する必要があると考えられます。
- E2Eテストを増やしすぎない。メンテコストが膨れ上がらないようにする
- 運用不安定なテストは即隔離
- 「たまに落ちる」テストは入れない方がマシ。CIの信頼性を守る
- そのサービスの「クリティカル・ユーザー・ジャーニー」を保証する
感想
どこまでE2Eテストを書くか?は組織の置かれている状況にもよると思いますが、
まずは「結論」を意識して コストと品質のバランス を取ることで、エンジニアが快適に働きつつサービスの安定稼働ができるよう目指していきたいと感じる所存です。