さまざまなテストタイプを組み合わせて、プロジェクトに合った合理的な戦略を立てる方法を学びます。
ご利用の再開ありがとうございます。前回の記事では、さまざまなテストタイプへのアプローチ方法とその内容について多くの基礎を築き、テストタイプの定義を明確にしました。このミーム画像を覚えていますか?これまで学んださまざまなテストタイプがどのように連携するのか、疑問に思われたかもしれません。

次に、その方法について説明します。この記事では、これらのテストタイプを組み合わせて合理的な戦略を立て、プロジェクトに合った戦略を選択する方法について説明します。
戦略をさまざまな形状と比較すると、その意味をより深く理解できます。以下に、それぞれの規模と開発範囲に応じた戦略の一覧を示します。
これらの戦略を詳しく見て、名前の意味を学びましょう。
テストの目標を決定する: これらのテストで何を達成したいのか?
優れた戦略の構築を始める前に、テストの目標を明確にしましょう。アプリケーションが十分にテストされたと判断するのはどのような場合ですか。
テストに関して、高いテスト カバレッジを達成することは、デベロッパーにとっての最終目標と見なされることがよくあります。しかし、これが常に最適なアプローチなのでしょうか。テスト戦略を決定する際に考慮すべき重要な要素がもう 1 つあります。それは、ユーザーのニーズを満たすことです。
デベロッパーは、他にも多くのアプリケーションやデバイスを使用します。この点において、あなたはこれらのシステムが「ただ動作する」ことに依存しているユーザーです。そして、アプリケーションやデバイスを動作させるために最善を尽くしている無数のデベロッパーに依存しています。この信頼に応えるために、デベロッパーの皆様も努力を重ねていらっしゃいます。したがって、最初の目標は常に、動作するソフトウェアをリリースしてユーザーに提供することです。これは、アプリケーションの品質を確保するために作成するテストにも当てはまります。Kent C. Dodds 氏が、Static vs Unit vs Integration vs E2E Testing for Frontend Apps という投稿で、このことを非常にうまくまとめています。
テストがソフトウェアの使用方法に似ているほど、信頼性が高くなります。
Kent C. 著Dodds
Kent は、これをテストに対する信頼を得ることと表現しています。適切なテストタイプを選択してユーザーに近づくほど、テスト結果の信頼性が高まります。つまり、ピラミッドの上位に上がるほど、信頼度が高くなります。ところで、ピラミッドとは何でしょうか。
テスト戦略の決定: テスト戦略の選択方法
最初のステップとして、要件のどの部分を確認して、要件が満たされていることを確認する必要があるかを判断します。効率的なコスト構造を維持しながら、どのテストタイプをどの程度の詳細レベルで使用すれば、最も高い信頼性を得られるかを把握します。多くのデベロッパーは、このトピックに類推を使用してアプローチしています。ここでは、よく知られている古典的なものから、最も一般的なものを紹介します。

定番: テスト ピラミッド
テスト戦略を探し始めると、最初にテスト自動化ピラミッドという例えを目にすることになるでしょう。このコンセプトは、Mike Cohn 氏が著書『Succeeding with Agile』で紹介したものです。その後、Martin Fowler 氏が実用的なテスト ピラミッドに関する記事でこのコンセプトを拡張しました。このピラミッドを視覚的に表すと、次のようになります。

この図に示すように、テスト ピラミッドは次の 3 つのレイヤで構成されています。
単位。これらのテストは、実行が速く、メンテナンスが簡単なため、ピラミッドのベースレイヤにあります。これらは分離されており、最も小さなテスト単位を対象としています。たとえば、非常に小さなプロダクトの一般的な単体テストをご覧ください。
統合。これらのテストは、実行速度は許容範囲内ですが、単体テストよりもユーザーに近いテストであるため、ピラミッドの中間に位置します。統合テストの例としては、API テストがあります。コンポーネント テストもこのタイプに分類できます。
E2E テスト(UI テストとも呼ばれます)。これらのテストでは、実際のユーザーとその操作をシミュレートします。このようなテストは実行に時間がかかるため、費用が高くなります。ピラミッドの最上部に位置します。
信頼度とリソース
前述のとおり、レイヤの順序は偶然ではありません。優先度とそれに対応する費用が表示されます。これにより、各レイヤに作成すべきテストの数を明確に把握できます。これは、テストタイプの定義ですでに確認しました。
E2E テストはユーザーに最も近いテストであるため、アプリケーションが意図したとおりに動作していることを最も確実に確認できます。ただし、完全なアプリケーション スタックとシミュレートされたユーザーが必要になるため、最もコストがかかる可能性があります。そのため、信頼性はテストの実行に必要なリソースと直接競合します。

ピラミッドは、単体テストに重点を置き、E2E テストでカバーされるケースを厳密に優先することで、この問題を解決しようとしています。たとえば、最も重要なユーザー ジャーニーや、不具合の影響を受けやすい場所などです。Martin Fowler 氏が強調しているように、Cohn 氏のピラミッドで最も重要な 2 つのポイントは次のとおりです。
- さまざまな粒度でテストを作成する。
- レベルが高くなるほど、テストの数は少なくなります。
ピラミッドが進化しました。テスト ピラミッドの調整
数年前から、ピラミッドに関する議論が行われてきました。このピラミッドは、テスト戦略を過度に単純化しているように見え、多くのテストタイプが除外されており、実際のプロジェクトすべてに適合するわけではありません。そのため、誤解を招く可能性があります。ピラミッドの形が崩れていませんか? Guillermo Rauch 氏は、これについて次のように述べています。
テストを作成する。そんなに多くありません主に統合。
Guillermo Rauch 著
これは、このテーマで最もよく引用される言葉の一つです。詳しく見ていきましょう。
- 「テストを作成する」。信頼を築くだけでなく、メンテナンスの時間を節約できるからです。
- 「多すぎない」100% のカバレッジが常に良いとは限りません。テストの優先順位が付けられず、メンテナンスが多くなるためです。
- 「主に統合」。ここでも、統合テストが重視されています。統合テストは、妥当な実行時間を維持しながら、日々の高い信頼性を提供することで、最も高いビジネス価値をもたらします。
このため、テスト ピラミッドについて再考し、統合テストに重点を移す必要があります。過去数年間に多くの適応が提案されてきました。ここでは、最も一般的な適応について見ていきましょう。
テスト ダイヤモンド
最初の適応は、テスト ピラミッドに見られるように、単体テストの過度の強調を排除することです。単体テストのカバレッジが 100% に達したとします。しかし、次にリファクタリングするときに、これらの単体テストの多くを更新する必要があり、テストをスキップしたくなるかもしれません。そのため、侵食されます。
その結果、統合テストに重点を置くことで、次のような形状になることがあります。

ピラミッドがダイヤモンドに進化します。前の 3 つのレイヤが表示されますが、サイズが異なり、ユニットレイヤがカットされています。
- 単位。以前に定義した方法で単体テストを作成します。ただし、エロージョンにつながる傾向があるため、優先順位を付け、最も重要なケースのみをカバーします。
- 統合。ご存じの統合テスト。単一ユニットの組み合わせをテストします。
- E2E。このレイヤは、テスト ピラミッドと同様に UI テストを処理します。E2E テストは、最も重要なテストケースに対してのみ作成するようにしてください。
テスト用ハニカム
Spotify が導入したもう 1 つの適応は、テスト ダイヤモンドに似ていますが、マイクロサービス ベースのソフトウェア システムにさらに特化しています。テスト ハニカムは、マイクロサービス ベースのソフトウェア システム用に作成するテストの粒度、スコープ、数を視覚的に表したものです。マイクロサービスはサイズが小さいため、最も複雑なのはサービス自体ではなく、他のサービスとのやり取りです。そのため、マイクロサービスのテスト戦略では、主に統合テストに焦点を当てる必要があります。

この形状はハニカムを連想させるため、この名前が付けられました。次のレイヤがあります。
- 統合テスト。Spotify の記事では、J. B. Rainsberger の言葉を借りれば、「別のシステムの正確性に基づいて合格または不合格となるテスト」です。このようなテストには、考慮する必要がある外部依存関係があります。逆に、システムが他のシステムを破壊する依存関係になる可能性もあります。他の類似の E2E テストと同様に、これらのテストは慎重に、最も重要なケースにのみ使用してください。
- 統合テスト。他のアダプテーションと同様に、このレイヤに重点を置く必要があります。このテストでは、サービスの正確性をより分離された方法で検証しますが、他のサービスと組み合わせて検証します。つまり、テストには他のシステムも含まれ、API テストなどを通じて、相互作用ポイントに重点が置かれます。
- 実装の詳細に関するテスト。これらのテストは、単体テストに似ています。単体テストは、自然に分離され、独自の内部的な複雑さを持つコードの部分に焦点を当てたテストです。
このテスト戦略について詳しくは、Martin Fowler 氏によるテスト ピラミッドとハニカムを比較した投稿と、Spotify の元の記事をご覧ください。
テストのトロフィー
統合テストに繰り返し重点が置かれていることがわかります。しかし、前の記事で紹介したもう 1 つのタイプは、理論的にはテストではありませんが、テスト戦略で考慮すべき重要な側面です。静的分析は、テスト ピラミッドと、これまで見てきたほとんどの適応に含まれていません。テスト トロフィーの適応では、統合テストに重点を置きながら、静的分析を考慮に入れます。テスト トロフィーは、Guillermo Rauch 氏の言葉から生まれ、Kent C. 氏によって開発されました。Dodds:

テスト トロフィーは、テストの粒度を少し異なる方法で表した比喩です。次の 4 つのレイヤがあります。
- 静的分析。この例えにおいて、コンパイラは重要な役割を果たします。すでに説明したデバッグ手順を実行するだけで、入力ミス、スタイルの誤り、その他のバグを検出できます。
- 単体テスト。単体テストは、最小単位が適切にテストされることを保証しますが、テスト トロフィーでは、テスト ピラミッドほど単体テストが重視されません。
- 統合。他の適応と同様に、コストと信頼性のバランスを最適に保つことが主な目的です。
- UI テスト。E2E テストやビジュアル テストなど、テスト トロフィーの最上位に位置するテストは、テスト ピラミッドでの役割と似ています。
テスト トロフィーの詳細については、Kent C. のブログ投稿をご覧ください。Dodds 氏の投稿をご覧ください。
UI に重点を置いたアプローチ
それはそれで良いのですが、戦略を「ピラミッド」、「ハニカム」、「ダイヤモンド」のいずれと呼ぶにしても、まだ何かが欠けています。テストの自動化は重要ですが、手動テストも依然として不可欠です。自動テストは、日常的なタスクを軽減し、品質保証エンジニアが重要な領域に集中できるようにする必要があります。自動化は、手動テストを置き換えるのではなく、補完するものです。手動テストと自動テストを統合して最適な結果を得る方法はありますか?
アイスコーンとカニのテスト
実際、テスト ピラミッドには、こうした UI に重点を置いたテスト方法に焦点を当てた 2 つの適応があります。どちらも信頼性が高いという利点がありますが、テスト実行速度が遅いため、当然コストが高くなります。
1 つ目のテスト アイスコーンは、ピラミッドを逆さにしたような形をしています。手動テストのステップがない場合は、テストピザとも呼ばれます。

アイスクリーム コーンは、手動テストまたは UI テストに重点を置き、単体テストにはほとんど重点を置いていません。これは、デベロッパーがテスト戦略についてあまり考えずに作業を開始したプロジェクトでよく見られます。ICE コードはアンチパターンと見なされていますが、それには正当な理由があります。リソースと手作業の観点からコストがかかるためです。
テストクラブはテストアイスコーンに似ていますが、E2E テストとビジュアル テストに重点を置いています。

このテスト戦略には、もう 1 つの側面があります。それは、アプリケーションが機能し、適切に表示されることを確認することです。テスト用のカニは、前の記事で定義したビジュアル テストの重要性を強調しています。コンポーネント テストと API テストに分かれる統合テストはさらにバックグラウンドに移行し、単体テストはさらに副次的な役割を担います。このテスト戦略について詳しくは、テストクラブに関する記事をご覧ください。
これらの 2 つのテスト戦略は、コストは高くなりますが、たとえば、必要なテストが少ない小規模なプロジェクトや、複雑さをカバーする必要性が低いプロジェクトなどでは、適切な選択肢となります。この場合、統合テストに重点を置いた本格的なテスト戦略は過剰な設計になる可能性があります。
これら 2 つのテスト戦略はコストがかかりますが、テスト数が少なく、複雑な処理をカバーする必要がない小規模なプロジェクトなどでは、有効な場合があります。この場合、統合テストに重点を置いた本格的なテスト戦略は、不必要に複雑になる可能性があります。
実践的なアドバイス: 戦略を立てましょう
これで、最も一般的なテスト戦略について学習しました。まず、古典的なテスト ピラミッドから始めて、その多くの適応について学びました。次に、これらのモデルをプロダクトに照らして評価し、プロジェクトに最適なモデルを決定する必要があります。この質問に対する回答は、誰もがよく使う「状況によって異なる」から始まります。ただし、精度が低下することはありません。

ここで説明したテスト戦略(および説明していないテスト戦略)の中から最も適切なものを選択するかどうかは、アプリケーションによって異なります。アーキテクチャ、要件、そして何よりもユーザーとその要件に適合している必要があります。これらはすべて、アプリケーションによって異なる場合があります。これは正常な現象です。最も重要な目標は、教科書的な定義ではなく、ユーザーにサービスを提供することです。
多くの場合、実際のテストを個別に分離して定義することは困難です。Martin Fowler 氏自身も、単体テストの場合など、定義が異なることのプラスの側面を強調しています。Justin Searls 氏がツイートで正しく述べているように、
[…] 明確な境界を確立し、迅速かつ確実に実行され、有用な理由でのみ失敗する、表現力豊かなテストを作成します。
Justin Searls 著
ユーザーが遭遇する可能性のある実際のエラーを報告するテストに焦点を当て、目標から目をそらさないようにします。テストは、100% のカバレッジを提供したり、どのテストタイプをどの割合で作成するかを議論したりするためではなく、ユーザーにメリットをもたらすように設計する必要があります。
ユーザーが遭遇する可能性のある実際の不具合を報告するテストに集中し、目標を見失わないようにしてください。テストは、100% のカバレッジを提供したり、特定のテストタイプの何パーセントを記述すべきかについての議論を巻き起こしたりするだけでなく、ユーザーにメリットをもたらすように設計する必要があります。