💥

E2Eテストの実装における落とし穴:シナリオベースから機能ベースへの移行で得た教訓

に公開

はじめに

ソフトウェア開発の現場において、エンドツーエンド(E2E)テストは、ユーザーが実際に体験するであろう一連の操作を通じて、システム全体の品質を保証するために欠かせないプロセスです。開発スピードの向上と品質維持を両立させるため、多くのチームがE2Eテストの自動化に取り組んでいます。

しかし、単に手動で行っていたテストシナリオをそのまま自動化しようとすると、予期せぬ問題に直面することがあります。本記事では、E2Eテスト自動化における「シナリオベーステスト」の課題と、その解決策としての「機能ベーステスト」への移行について解説します。

※ この記事は【めぐろLT #25 「私、これ自動化しました!」】で発表した内容を再構成したものです。

https://speakerdeck.com/isosea/e2edeshou-dong-tesutowozi-dong-hua-siyoutositakedosonnajian-dan-ziyanakatutahua

E2Eテストとは? - 基本の確認

まず、E2Eテストの定義と特性をおさらいしましょう。

  • 定義: 国際ソフトウェアテスト資格認定委員会(ISTQB)によれば、A test type in which business processes are tested from start to finish under production-like circumstances.「ビジネスプロセスを本番同等の環境で最初から最後まで検証するタイプのテスト」とされています。[1]
  • 位置づけ: ユニットテスト、インテグレーションテスト、E2Eテストから成るテストピラミッドの頂点に位置し、最もユーザーの利用状況に近い視点でのテストです。
  • メリット:
    • システム全体の動作をユーザー視点で確認でき、信頼性が高い。
    • 複数のコンポーネントやシステム間の連携を確認できる。
  • デメリット:
    • テストコードの実装や維持にコストがかかる。
    • 実行に時間がかかる。
    • テスト環境や外部システムの状態に影響されやすく、結果が不安定になることがある(Flaky Test)。

これらの特性から、E2Eテストは全ての操作パスを網羅するのではなく、システムのコアとなる重要なユースケースに絞って実装するのが現実的かつ効果的なアプローチとされています。

E2Eテスト自動化への挑戦:初期アプローチ「シナリオベーステスト」

私たちのチームでは、手動テストの工数削減と品質向上を目指し、E2Eテストの自動化に着手しました。

最初のステップとして、対象となるシステムのユーザー属性(例:荷物を送りたい「荷主」、物流サービスを提供する「ハコベル」、荷物を運ぶ「運送会社」)と、それぞれのユーザーが利用する主要な機能(例:案件登録、受発注管理、運行管理)を整理しました。

次に、これらの機能をつなぎ合わせ、実際の業務フローに近いユーザーシナリオを作成しました。例えば、以下のような一連の流れを一つのテストシナリオとして定義しました。

  • シナリオ1: 荷主が配送案件をシステムに登録 → 運送会社がその案件を受注 → 運送会社が配送完了を報告
  • シナリオ2: 荷主が配送案件をシステムに登録 → 運送会社がその案件を受注 → 何らかの理由で案件をキャンセル

これらの主要な業務シナリオを自動テストとして実装することで、手動テストの代替となることを期待しました。

シナリオベーステストで露呈した3つの課題

一見、合理的に見えるシナリオベースのアプローチですが、実際に運用してみると、いくつかの課題が明らかになりました。

  1. テストの焦点が曖昧になる問題:
    例えば、「シナリオ1」は「案件登録」「受注」「配送完了」という複数の機能を含んでいます。このテストが失敗した場合、どの機能に問題があったのか、このテストが具体的に何を保証しているのかが、テストコードを読んだだけでは分かりにくくなります。他の開発者やQA担当者にとって、テストの意図を理解し、手動テストを確実に代替できているか判断するのが困難になります。
  2. テストステップの重複による実行時間の増大:
    「シナリオ1」と「シナリオ2」は、どちらも「案件登録」と「受注」のステップを含んでいます。このように、異なるシナリオ間で同じ操作が繰り返し実行されるため、テストスイート全体の実行時間が不必要に長くなってしまいます。テストケースが増えるほど、この冗長性は無視できない問題となります。
  3. テストの連鎖による影響範囲の拡大:
    シナリオベースのテストでは、一連のステップが順番に実行されます。もしシナリオの初期段階(例:「案件登録」)でエラーが発生してテストが失敗すると、後続のステップ(例:「受注」や「配送完了」)の検証は行われません。これにより、失敗箇所によっては、他の機能が正常に動作するかどうかを確認する機会が失われてしまいます。

改善策:より明確で効率的な「機能ベーステスト」へ

シナリオベーステストの課題を克服するため、私たちのチームはテストの粒度を見直すことにしました。ビジネスプロセス全体を一つの大きなテストケースとして扱うのではなく、個々の機能を独立して検証する「機能ベーステスト」のアプローチへと移行しました。

先の「シナリオ1」を機能ベースで再構成すると、以下のようになります。

  • テスト1: 案件登録機能のテスト
    • 目的: 荷主が案件を正しく登録できることを検証する。
    • 操作: 案件登録画面から必要な情報を入力し、登録を実行する。
    • 検証: 登録された案件データが正しいことを確認する。
  • テスト2: 受注機能のテスト
    • 目的: 運送会社が案件を正しく受注できることを検証する。
    • 前提条件: 事前にテスト用の案件データが存在する状態を用意する(API経由でのデータ作成、DBへの直接投入、あるいはUI操作による事前登録など)。
    • 操作: 対象の案件を選択し、受注を実行する。
    • 検証: 案件のステータスが「受注済み」に更新されることなどを確認する。
  • テスト3: 配送完了機能のテスト
    • 目的: 運送会社が配送完了を正しく報告できることを検証する。
    • 前提条件: 事前にテスト用の受注済み案件データが存在する状態を用意する。
    • 操作: 対象の案件を選択し、配送完了の操作を実行する。
    • 検証: 案件のステータスが「配送完了」に更新されることなどを確認する。

この機能ベースのアプローチには、以下のメリットがあります。

  • テスト内容の明確化: 各テストが検証する機能が明確になり、意図が伝わりやすくなります。
  • 重複の排除と効率化: 機能ごとに独立しているため、冗長なステップがなくなり、テスト実行時間が短縮されます。
  • 影響範囲の限定: あるテストが失敗しても、他の独立した機能テストの実行には影響しません。デバッグや修正が容易になります。
  • メンテナンス性の向上: 機能仕様の変更があった場合、対応するテストケースを特定し、修正するのが容易になります。

機能ベーステストの注意点と対策

一方で、機能ベーステストには以下のような注意点があります。

  • ビジネスフロー全体の検証が手薄になる可能性: ユーザーが実際にシステムを利用する際の一連の流れで発生する問題を見逃す可能性があります。例えば、「案件登録」機能と「受注」機能がそれぞれ単体では正しく動作しても、登録された案件データが受注プロセスで正しく引き継がれない、あるいは特定の順番で操作した場合にのみ発生する不具合などは、機能単位のテストだけでは検知しにくい場合があります。
  • テストデータの準備・管理コストの増加: 各機能テストを独立して実行可能にするためには、テストごとに適切な前提条件を整える必要があります。これを実現するために、テスト実行前にAPIを呼び出してデータを作成したり、最低限の画面操作を行ったりするなどの「セットアップ処理」が必要になります。これには、データ生成ロジックの実装、様々なデータパターンの準備、テスト後のデータ後片付け、データ整合性の維持といったコストが伴います。

これらの注意点を踏まえ、私たちのチームではリスクベースでのアプローチを採用しています。これは、すべての機能に均一な労力をかけるのではなく、変更頻度や過去の障害実績といった潜在的なリスクに応じてテストの重点や粒度を調整する考え方です。

このアプローチにより、機能ベーステストの課題である「ビジネスフロー検証の漏れ」や「データ準備コスト」といった懸念を、リスクの高い領域に注力することで抑制し、テスト自動化の費用対効果を高めることを目指しています。

まとめ:E2Eテスト自動化成功の鍵は「適切な粒度」

手動で行っているE2Eテストを自動化する際、単に操作手順をなぞるだけでなく、テストの粒度をいかに設計するかが重要な観点となります。

ユーザーシナリオ全体を一つのテストとするアプローチは、一見ユーザーの体験を忠実に再現しているように思えますが、実際にはテストの目的の曖昧さ、実行時間の増大、失敗時の影響範囲の広がりといった課題を生む可能性があります。

これらの課題を回避し、効果的でメンテナンスしやすいE2Eテストスイートを構築するためには、個々の機能を独立して検証する「機能ベース」のアプローチが一つの解決策となり得ます。これは、私たちが普段、手動で「このボタンは正しく動くか」「この登録は成功するか」と一つ一つの機能を確認する作業と本質的に同じです。

E2Eテスト自動化においては、手動テストを行う際の思考プロセス、つまり適切な粒度を意識してテストを設計することが、その効果を最大限に引き出すための重要なポイントと言えるでしょう。

脚注
  1. https://glossary.istqb.org/en_US/term/end-to-end-testing ↩︎

Hacobell Developers Blog

Discussion