web-dev-qa-db-ja.com

統合テストは単体テストよりも多くの価値を提供する必要がありますか?

この質問をするために、私はそれを読んでいる全員が同じページにいることを確実にするためにいくつかの用語を定義する必要があります:

  • 単体テストは、すべての依存関係が何らかの方法でモック/スタブされた単一のクラスのテストです。
  • このコンテキストでの統合テストとは、システム内の選択されたオブジェクトと、依存関係が疑われる依存関係を統合することを意味します。たとえば、外部の共同作業者(データベースやリモートのサードパーティなど)はモック化されているかもしれませんが、内部システムもモック化されている可能性があります(たとえば、常に機能するように認証メカニズムをモックアウトしています)。アイデアは、システムの重要なサイズでない部分をスピンアップし、それが動作することを確認することです。
  • 機能テストは、システム全体を起動し、望ましい結果を達成するためにシステムを突っ込んでいます。この質問の目的のために、それは実際の外部のcollに対するものかもしれません

テストピラミッドの観点から、70%のユニットから20%の統合から10%の機能テストまでを統合する必要があります。

上記のように私の質問は次のとおりです:ユニットテストの大規模なスイートがある環境で作業しましたが、統合テストが不十分であるか、機能テストが存在しないため、実行時にバグがまだ表面化しています。特定のクラスの優れたユニットカバレッジがあっても、そのクラスの実際の使用方法/システムの他の部分への配線方法には、通常、ユニットレベルで実際に把握できるよりも多くのバグが含まれています。通常、これらのバグは統合/機能テストレベルで検出されます。

ユニットテストを許可すると、システムをより多くの状態に置くことができ、実行速度が大幅に向上しますが、バグ検出機能として、実際にコードパスを駆動する統合/機能レベルのテストと比較して低下します。他の人とこのポイントを上げると、通常の応答は「ああ、統合テストは実際には作成していない単体テストを見つけている!」と言うことです。これは一見有効なようですが、コードをテストしているだけです2回:完全なカバレッジでの統合レベルで1回と、カバレッジのレベルを保証できないユニットレベルで1回。ただし、両方のセットを維持する必要があります。

私の質問は、統合テストのセットアップが最小限に抑えられているか、共通のテストセットアップライブラリで抽象化されている場合、統合テストを単体テストの「最初の行」として使用しないのはなぜですか?すべてを2回テストすることの実際の価値は何ですか?

5
ahjmorton

これはAです。2回クリックした後、カウントAに尋ねると、Aは2を与えます。 Aがこのように機能することを知っているのは、それを実行するコードを見て、それが実行されるのを見たからです。中を見なくてもAがどうあるべきかを理解しているように感じます。

これがシステムabcxyzです。起動すると、走行距離計(またはスコアボード、または数字の表示)のようなGIFが生成されます。多くのワイルドで素晴らしい方法で構成できます。しかし、それを実行する統合テストコードを見てみると、まあ...何を期待しているのか、何がカウントされているのか、どこでこれらのイメージを取得しているのかを理解するには、少し時間がかかります。あなたはこれが何であるかを知っていると思いますが、変更を加えるときは、abcxyzを何が使用しているかを理解する必要があることに気づきました。したがって、システムの残りの部分を確認します。あなたは読み続けます...そして読みます...ため息...

私は両方のテストを受けるのが好きです。ユニットテストが、筆者がAにとって本当に重要だと思ったことを理解しているという自信が好きです。クラス定義よりも、よくできた単体テストの方が読みやすいと思います。

私は向きを変えて、統合テストについての私の理解を知らせるためにそれを使いたいです。単体テストなしでこれを行うと、ブレンダーに入れてから4コースのディナーを食べるような気分になります。できます。しかし、残念。

そして、それはコードを読むことのようなものです。

読みやすいコードの記述方法について、コードの記述が簡単になるようなことは決して信用しないでください。

5
candied_orange

これは、トップダウン開発とボトムアップ開発の問題です。大きなマシンを構築する場合、最初にシステム全体を構築してからそれを全体としてテストしますか、それとも全体を組み立てる前に各コンポーネントを個別に開発してテストしますか?正解は、両方を実行することです。確かにシステム全体をテストする必要がありますが、コンポーネントを個別にテストすることには多くの利点もあります。

  • コンポーネントを個別に並行して開発できます。
  • エラーを早期に発見します(テストする前に、マシン全体がすべて終了するまで待つ必要はありません)。
  • コンポーネントを個別にテストする場合は、エラーを特定するのがはるかに簡単です。
  • (他の保護手段により)システム全体で複製することが不可能なEdgeのケースとエラー条件をテストできます。
  • テストの記述ははるかに簡単です。
  • コンポーネントを個別にテストすると、明確に定義されたインターフェイスと動作、および最小限の依存関係で各コンポーネントを設計する必要があります。
4
JacquesB

テストの詳細レベルを上げることの利点は、問題の存在だけでなく、正確な問題を特定できることです。

また、要件のテストと、単体テストを行うシステムの個々の部分の要件の定義についても検討する必要があります。

たとえば、オファーやモノに基づいて製品のバスケットの価格を返すBasketPriceCalculatorがあるとします。 2対1のオファーの単体テストを行って失敗した場合、そのクラスのオファーに問題があることがわかります。チェーン内のいずれかのコンポーネントが失敗した場合、同等の統合または機能テストが失敗する可能性があるのに対し、.

また、バスケットに7個を超えるアイテムがある場合、BasketPriceCalculatorがエラーをスローするという特定の要件があるかもしれません。エラーを処理し、他のアクションを実行する可能性がある製品全体ではなく、コンポーネントに固有であるため、依存関係を含めずにその要件をテストしたいと思います。

全体的に私はあなたに同意します。統合テストはユニットテストよりも重要であり、モックモックと実際の依存関係を使用してすべてのユニットテストを実行してはならない理由は実際にはありません。データ駆動テストでこれを行います。

機能テストはさらに重要であり、実行速度が遅くても、機能テストと見なすことができるすべてのシナリオを実行しない理由は実際にはありません。結局のところ、ユーザーはそうするでしょう。

しかし、実際には、ゼロから何かを開発する場合、機能テストを記述できる機能するアプリから始める必要はありません。与えられたいくつかのルールに基づいてバスケットの価格を計算する小さなコンポーネントから始めます。したがって、最初にそのビットの単体テストを記述します。

2
Ewan