テストする必要があるものと除外できるものを特定します。
以前の記事では、テストケースの基本と含めるべき内容について説明しました。この記事では、技術的な観点からテストケースの作成について深く掘り下げ、各テストに含めるべき内容と避けるべき事項について詳しく説明します。基本的には、「テストすべきこと」や「テストすべきでないこと」といった長年の問いに対する答えを学びます。
一般的なガイドラインとパターン
単体テスト、統合テスト、エンドツーエンド テストのいずれを実行するかにかかわらず、具体的なパターンとポイントが重要になります。これらの原則は、両方のタイプのテストに適用でき、また適用すべきであるため、最初に確認することをおすすめします。
デザインはシンプルに
テストを作成するうえで最も重要なことの一つは、シンプルにすることです。脳の能力を考慮することが重要です。メインの本番環境コードはかなりのスペースを占有するため、さらに複雑になる余地はほとんどありません。これは特にテストに当てはまります。
利用できるヘッドスペースが限られると、テスト作業でリラックスできる可能性があります。そのため、テストではシンプルさを優先することが極めて重要です。実際、Yoni Goldberg による JavaScript テストのベスト プラクティスでは、ゴールデン ルールの重要性が強調されています。複雑な数式ではなく、アシスタントのような感覚でテストできるべきです。つまり、テストの意図を一目で理解できる必要があります。
複雑さに関係なく、すべての種類のテストでシンプルさを目指す必要があります。実際、テストが複雑になるほど、その簡素化が重要になります。これを実現する 1 つの方法は、テストを可能な限りシンプルにし、必要なものだけをテストするフラットなテスト設計です。つまり、各テストには 1 つのテストケースのみを含め、テストケースは 1 つの特定の機能をテストすることに重点を置く必要があります。
以下の視点から考えてみてください。失敗したテストを読む際に、何が問題だったかを簡単に特定できるようにする必要があります。そのため、テストをシンプルで理解しやすいものにすることが重要です。これにより、問題が発生したときにすばやく特定して修正できます。
価値をテストする
また、フラットなテスト設計は集中力を高め、テストが有意義であることを確認するのに役立ちます。テストを作成する目的は、カバレッジの向上だけを目的とするものではなく、必ず目的を持たせることです。
実装の詳細をテストしない
テストでよく見られる問題として、コンポーネントやエンドツーエンド テストでセレクタを使用するなど、実装の詳細をテストするためのテストが設計されることが多くあります。実装の詳細とは、コードのユーザーが通常は使用しない、または目にしない、あるいは認識さえしない情報のことです。テストでは、偽陰性と偽陽性という 2 つの大きな問題が発生する可能性があります。
偽陰性は、テスト対象のコードが正しいにもかかわらずテストが失敗すると発生します。これは、アプリケーション コードのリファクタリングによって実装の詳細が変更された場合に発生することがあります。一方、テスト対象のコードが正しくない場合でも、テストに合格すると誤検出が発生します。
この問題の解決策の一つは、さまざまなタイプのユーザーを考慮することです。エンドユーザーとデベロッパーは手法が異なり、コードの使い方も異なる場合があります。テストを計画する際には、ユーザーが何を見たり操作したりするのかを考慮し、実装の詳細ではなく、そうした要素に基づいてテストを行うことが重要です。
たとえば、変更されにくいセレクタを選択すると、テストの信頼性が向上します(CSS セレクタではなくデータ属性)。詳しくは、Kent C. Dodds の記事をご覧いただくか、今後の情報にご注目ください。
モック: コントロールを失わないように
モックは、単体テストのほか、場合によっては統合テストで使用される広範なコンセプトです。アプリケーションを完全に制御する依存関係をシミュレートするために、架空のデータやコンポーネントを作成します。これにより、テストの分離が可能になります。
テストでモックを使用すると、予測可能性、懸念事項の分離、パフォーマンスが向上します。また、人間が関与する必要があるテスト(パスポートの確認など)を実施する必要がある場合は、モックを使用して隠蔽する必要があります。以上の理由から、モックは検討すべき貴重なツールです。
同時に、モックは実際のユーザー エクスペリエンスではなくモックであるため、テストの精度に影響を与える可能性があります。そのため、モックとスタブを使用するときには注意する必要があります。
エンドツーエンド テストで模擬試験を行うべきですか?
一般的には違います。ただし、嘲笑することは命を救うこともあるため、完全に除外することはしないでください。
サードパーティの決済機関のサービスに関係する機能のテストを作成しているとします。お客様は、プロバイダが用意したサンドボックス環境にいるため、実際の取引は行われません。残念ながら、サンドボックスに不具合があり、テストが失敗します。決済機関が修正を行う必要があります。プロバイダによって問題が解決されるのを待つだけです。
この場合は、制御できないサービスへの依存度を下げる方がメリットがある可能性があります。テストの信頼度が低下するため、統合テストやエンドツーエンド テストでは、モックを慎重に使用することをおすすめします。
テストの詳細: 推奨事項と禁止事項
では、テストには何が含まれるでしょうか。テストの種類に違いはありますか?主なテストタイプごとに調整された特定の側面を詳しく見てみましょう。
優れた単体テストに必要な要素
理想的かつ効果的な単体テストに必要な条件は次のとおりです。
- 特定の側面に焦点を当てます。
- 単独で運用する。
- 小規模なシナリオが含まれる。
- わかりやすい名前を使用します。
- 該当する場合は AAA パターンに従います。
- 包括的なテスト カバレッジを保証する。
推奨 ✅ | 避けるべきこと ❌ |
---|---|
テストの規模はできるだけ小さくしてください。テストケースごとに 1 つの項目をテストします。 | 大規模なテストを作成します。 |
テストは常に分離し、ユニット外の必要なものをモックします。 | 他のコンポーネントやサービスを含めます。 |
テストを独立させる。 | 以前のテストを利用する、またはテストデータを共有する。 |
さまざまなシナリオや手順を説明します。 | 最大限ハッピーパスやネガティブ テストだけにとどめましょう。 |
内容がすぐにわかるように、わかりやすいテストタイトルを付けます。 | 関数名のみでテストし、結果的に十分な説明にならない(testBuildFoo() または testGetId() )。 |
特にこの段階では、適切なコード カバレッジまたは幅広いテストケースを目指します。 | すべてのクラスからデータベース(I/O)レベルまでのテストを行います。 |
優れた統合テストの条件
理想的な統合テストは、単体テストといくつかの基準を共有しています。ただし、考慮すべき点がいくつかあります。優れた統合テストの条件:
- コンポーネント間のインタラクションをシミュレートします。
- 実際のシナリオをカバーし、モックまたはスタブを使用します。
- パフォーマンスを考慮してください。
推奨 ✅ | 避けるべきこと ❌ |
---|---|
統合ポイントをテストする: 各ユニットが相互に統合したときに正常に連携することを確認します。 | 単体テストは、各ユニットを個別にテストします。 |
現実のシナリオをテストする: 実世界のデータから派生したテストデータを使用します。 | 繰り返し自動生成されたテストデータ、または実際のユースケースを反映していないその他のデータを使用する。 |
外部依存関係にモックとスタブを使用して、完全なテストの制御を維持します。 | サードパーティ サービスへの依存関係を作成する(外部サービスへのネットワーク リクエストなど) |
各テストの前後にクリーンアップ ルーティンを使用します。 | テスト内でクリーンアップ手段を使用することを忘れないでください。そうしないと、テストを適切に分離できないため、テストの失敗や誤検出につながる可能性があります。 |
優れたエンドツーエンド テストに必要な要素
包括的なエンドツーエンド テストでは、次のことを行う必要があります。
- ユーザー操作を複製する。
- 重要なシナリオを網羅する。
- 複数のレイヤにまたがります。
- 非同期オペレーションを管理する。
- 結果を確認します。
- パフォーマンスを考慮する。
推奨 ✅ | 避けるべきこと ❌ |
---|---|
API を活用したショートカットを使用します。詳細 | beforeEach フックを含むすべてのステップで UI インタラクションを使用します。 |
各テストの前にクリーンアップ ルーティンを使用します。ここでは副作用が生じるリスクが高いため、単体テストや統合テストよりもテストの分離に注意を払ってください。 | 各テストの後にクリーンアップを忘れないでください。残った状態、データ、副作用をクリーンアップしないと、後で実行する他のテストに影響します。 |
エンドツーエンド テストはシステムテストとみなします。つまり、アプリケーション スタック全体をテストする必要があります。 | 単体テストは、各ユニットを個別にテストします。 |
テスト内でモックを最小限に抑えるか、モックを使用しない。外部依存関係をモックする場合は慎重に検討してください。 | モックを多用する。 |
パフォーマンスとワークロードを考慮してください。たとえば、同じテストで大規模なシナリオを過剰にテストしないようにします。 | ショートカットを使用せずに大規模なワークフローに対応。 |