私のC#ソリューションには、すべてのビルドで実行できる単体テスト(xUnit)を含むTestsプロジェクトがあります。ここまでは順調ですね。
また、すべてのビルドで実行されるわけではありませんが、要求に応じて実行できる統合テストを追加したいと思います。それらをどこに配置し、単体テストと統合テストをどのように分離しますか?同じ[Fact]属性を持つ同じソリューションにある場合、まったく同じ方法で実行されます。
推奨されるアプローチは何ですか?統合テスト用の2番目の個別のテストプロジェクトですか?
分離はユニット対統合テストではありません。分離は高速対低速のテストです
実行を簡単にするためにこれらのテストをどのように整理するかは、実際にはあなた次第です。個別のフォルダーが適切な出発点ですが、特性や[Fact]
などの他の注釈も同様に機能します。
統合テストと単体テストを構成するものについて、ここには根本的な誤解があると思います。 Flaterの回答の冒頭は、2つの違いを示しています(そして、はい、残念ながら、この質問についてはすでに回答を引用しておきます)
フレーター 言った:
単体テストと統合テストの違いは、それらが異なるものをテストすることです。簡単に言えば:
- 単体テストは、1つの処理が本来の機能を果たしているかどうかをテストします。 (「トミーはボールを投げることができますか?」または「ティミーはボールをキャッチできますか?」)
- 統合テストでは、2つ(またはそれ以上)のものが一緒に機能するかどうかをテストします。 (「トミーはティミーにボールを投げることができますか?」)
そして、マーティン・ファウラーからのいくつかの支持文学:
統合テストは、独立して開発されたソフトウェアのユニットが互いに接続されているときに正しく機能するかどうかを判断します。ソフトウェアの拡散規格によっても用語が不鮮明に業界なので、私の執筆でそれを使用することに注意してきました。特に、多くの人々は統合テストのスコープが必然的に広いと想定していますが、より狭いスコープでより効果的に実行できます。
(強調、私の)。その後、彼は統合テストについて詳しく説明します。
統合テストのポイントは、名前が示すように、個別に開発された多くのモジュールが期待どおりに連携するかどうかをテストすることです。
(強調、彼)
統合テストの「より狭い範囲」に関して:
問題は、統合テストを構成するものについて、少なくとも2つの異なる概念があることです。
狭い統合テスト
- 別のサービスと通信する私のサービスのコードの部分のみを行使する
- プロセス内またはリモートで、これらのサービスのテストダブルを使用する
- したがって、多くの場合、スコープが限定された多くのテストで構成されます。多くの場合、スコープはユニットテストよりも大きくありません(通常、ユニットテストに使用されるのと同じテストフレームワークで実行されます)
広範な統合テスト
- すべてのサービスのライブバージョンが必要であり、実質的なテスト環境とネットワークアクセスが必要です
- 対話を担当するコードだけでなく、すべてのサービスを通じてコードパスを実行する
(強調、私の)
ここで、問題の根源に取り掛かります。統合テストは、高速または低速で実行できます。
統合テストが迅速に実行される場合、単体テストを実行するときはいつでもそれらを常に実行します。
統合テストの実行速度が遅い場合、ファイルシステム、データベース、またはWebサービスなどの外部リソースとやり取りする必要があるため、統合テストは継続的な統合ビルド中に実行し、開発者がコマンドを実行する必要があります。たとえば、コードレビューの直前に、変更したコードに適用されるすべてのテスト(単体テスト、統合テストなど)を実行します。
これは、開発者の時間と開発ライフサイクルの早い段階で欠陥を見つけることの間の最良のバランスです。
単体テストと統合テストの違いは、それらが異なるものをテストすることです。簡単に言えば:
私が提供した統合テストの例は非常に単純に見えるかもしれないので、単体テストの例を実行した後でテストする価値はありません。ただし、説明のためにこれを単純化しすぎていることに注意してください。
統合テスト。すべてのビルドで実行されるわけではありませんが、要求に応じて実行できます
これは、実際に統合テストに取り組むべき方法ではありません。これらは単体テストと同様に不可欠であり、同じスケジュールで実行する必要があります。
単体テストと統合テストは、「テストパッケージ」の2つの部分と考える必要があります。テスト時に実行する必要があるのはこのパッケージです。アプリケーションの目的のhalfのみをテストし、意味のある決定的なテストであると見なしても意味がありません。
一般的なテストスケジュールに統合テストを追加しなくても、ポップアップするテストの失敗を無視するだけです。テストが存在するのは、失敗のアラートを受け取りたいからです。なぜ、それらのアラートを意図的に非表示にするのでしょうか。これは、ラジオをオンにしてから、指を耳に当てるのと同じです。
統合テストから単体テストをどのように分離しますか?
これらは通常、異なるプロジェクト(通常は同じソリューション)に分離されていますが、それは技術的な要件ではなく、コードベースを構造化する方法です。
同じ[Fact]属性を持つ同じソリューションにある場合、まったく同じ方法で実行されます。
すでに述べたように、それらをまったく同じ方法で実行することは、あなたがやるべきことです。
私はあなたが「同じプロジェクト内」を意味し、「同じソリューション内」ではないことを想定しています。多くの場合、コードベースの構造化の問題として別々のプロジェクトに分離されますが、ユニットテストと統合テストを分離するように強制する技術的な要件はありません。同じプロジェクトにそれらを配置することもできます。これは、少数のテストのみを使用する小さなコードベースには意味があります。
「1つのサイズですべてに対応できる」というアプローチはありません。
いくつかのショップは、単体テストと同じプロジェクトにそれらを持っていますが、他のショップは、それらを単独で別のプロジェクトに置くことを好みます。
どのように行うにせよ、ビルドマネージャーや開発者が適切であると判断した場合にテストのサブセットを実行するようにビルドサーバー(ある場合)を設定できるように、フラグを立てることをお勧めします。
私は正直に言うとxUnitには不向きですが、これは trait で実行できるようです。
これらの準備が整ったら、開発者はローカルで実行したいテストのカテゴリを選択して、開発をスピードアップできます。
それはおそらくテストフレームワークに依存します(使用していますか?)
JUnit 4/5の場合、個別のテストスイートがあります。
1つのセットをローカルで実行し、別のセットをグループレベルのプルリクエスト(すべてのjarの単体テスト)の前に実行します。 126k統合テストは、実行に数時間かかる可能性があります(エンドツーエンド/ Selenium、Weblogic、Oracle RDBMS、およびOracle BI Publisher、Docker、他の多くのサードパーティCOTSを使用した統合テスト)は、リリースプルリクエストの前に実行されます。 6時間ごとに実行します。
もちろん、必要に応じて、これらのテストをローカルで実行することもできますが、ローカルのDockerイメージに必要な期間と特別なセットアップのために面倒なので、通常は、グループビルドサーバーがどのように処理するかを待って確認します。
おそらく「正しい」答えはありませんが、私にはいくつかの簡単な経験則があります。
テストでは、ビジネス(ユースケース)要件が満たされているかどうかを確認する必要があります。これは、テストする単純または複雑なコンポーネントがないことを意味します。新しいテストを追加する唯一の理由である要件があります。
APIのみがテストされ、実装はテストされません。
モックは最低限回避する必要があります(非常に低速または高価なリソースの場合のみ)。
単体テストは、展開する必要なく、コードのレベルで実行できます。
統合テストでは、コンポーネントがシステムに正しく統合されていることを確認します。つまり、コンポーネントをデプロイする必要があります。
この違いは、展開されているかどうかにかかわらず、展開プロセス(パイプラインステージ)の場所を決定します。