335

単体テストと統合テストのいわゆる教科書的な定義を知っています。私が興味を持っているのは、単体テストを作成する時期です...できるだけ多くのクラスのセットをカバーするように記述します。

たとえば、クラスがある場合、クラスWordの単体テストをいくつか作成しWordます。次に、Sentenceクラスの作成を開始し、クラスと対話する必要がある場合は、少なくともそれらが対話する場所でWord両方をテストするように単体テストを作成することがよくSentenceあります。Word

これらのテストは、これら 2 つのクラスの統合をテストするようになったため、本質的に統合テストになりましたか? それとも、2 つのクラスにまたがる単なる単体テストですか?

一般に、この不確実な行のために、実際に統合テストを作成することはめったにありません...または完成品を使用して、すべての部分が実際の統合テストで適切に機能するかどうかを確認します.手動であり、範囲を超えて繰り返されることはめったにありません.個々の機能の?

統合テストを誤解していますか、それとも統合テストと単体テストの違いは本当にほとんどないのでしょうか?

4

20 に答える 20

328

私にとっての重要な違いは、統合テストは現実に近いシナリオでコードにストレスを与えるため、機能が機能しているか壊れているかを明らかにすることです。1 つまたは複数のソフトウェア メソッドまたは機能を呼び出し、期待どおりに動作するかどうかをテストします。

反対に、単一のメソッドをテストする単体テストは、すべての依存関係を明示的にモックするため、ソフトウェアの残りの部分が正しく機能しているという (しばしば間違った) 仮定に依存します。

したがって、何らかの機能を実装するメソッドの単体テストが緑色であっても、その機能が機能しているとは限りませ

次のようなメソッドがあるとします。

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  Log.TrackTheFactYouDidYourJob();
  return someResults;
}

DoSomething顧客にとって非常に重要です。それは機能であり、重要な唯一のものです。そのため、通常、それを主張する Cucumber 仕様を作成します。つまり、機能が機能しているかどうかを確認して伝達したいのです。

Feature: To be able to do something
  In order to do something
  As someone
  I want the system to do this thing

Scenario: A sample one
  Given this situation
  When I do something
  Then what I get is what I was expecting for

疑いの余地はありません。テストに合格すれば、機能する機能を提供していると断言できます。これがビジネス価値と呼べるものです。

単体テストを作成する場合は、DoSomething(いくつかのモックを使用して) 残りのクラスとメソッドが機能している (つまり、メソッドが使用しているすべての依存関係が正しく機能している) ふりをして、メソッドが機能していることをアサートする必要があります。

実際には、次のようにします。

public SomeResults DoSomething(someInput) {
  var someResult = [Do your job with someInput];
  FakeAlwaysWorkingLog.TrackTheFactYouDidYourJob(); // Using a mock Log
  return someResults;
}

これは、依存性注入、ファクトリ メソッド、モック フレームワーク、またはテスト対象のクラスを拡張することで実行できます。

にバグがあるとしLog.DoSomething()ます。幸いなことに、Gherkin 仕様はそれを見つけ、エンドツーエンドのテストは失敗します。

機能が機能しないのは、 が機能してLogいないからではなく、 が壊れ[Do your job with someInput]ているからです。ところで、[Do your job with someInput]その方法については単独で責任を負います。

また、Logが 100 の他の機能、100 の他のクラスの 100 の他のメソッドで使用されているとします。

はい、100 個の機能が失敗します。しかし、幸いなことに、100 のエンド ツー エンド テストも失敗し、問題が明らかになりました。そして、はい:彼らは真実を語っています.

これは非常に有益な情報です。製品が壊れていることはわかっています。また、非常に紛らわしい情報でもあります。どこに問題があるかについては何も教えてくれません。根本的な原因ではなく、症状を伝えます。

しかし、DoSomethingの単体テストは緑色Logです。壊れないように構築された偽の を使用しているためです。そして、はい:明らかに嘘をついています。壊れた機能が動作していることを伝えています。どのように役立ちますか?

(DoSomething()の単体テストが失敗した場合は、[Do your job with someInput]いくつかのバグがあることを確認してください。)

これが壊れたクラスを持つシステムであるとします: クラスが壊れたシステム

1 つのバグがいくつかの機能を壊し、いくつかの統合テストが失敗します。

1 つのバグがいくつかの機能を壊し、いくつかの統合テストが失敗します

一方、同じバグは 1 つの単体テストだけを壊します。

同じバグで 1 つの単体テストが壊れる

ここで、2 つのシナリオを比較します。

同じバグが壊れる単体テストは 1 つだけです。

  • 壊れたものを使用しているすべての機能Logは赤です
  • すべての単体テストは緑色で、単体テストのみLogが赤色です

実際、壊れた機能を使用するすべてのモジュールの単体テストは、モックを使用して依存関係を削除したため、緑色です。つまり、完全に架空の理想的な世界を走っているのです。そして、これがバグを特定して探す唯一の方法です。単体テストとは、モッキングを意味します。モックしていない場合は、単体テストではありません。

違い

統合テストは、が機能していないかを示します。しかし、問題がどこにあるのかを推測するのには役に立ちません。

単体テストは、バグの正確な場所を示す唯一のテストです。この情報を引き出すには、他のすべての依存関係が正しく機能するはずの模擬環境でメソッドを実行する必要があります。

そのため、「または、2つのクラスにまたがる単なる単体テストですか」という文は、どういうわけかずれていると思います。単体テストが 2 つのクラスにまたがることはありません。

この返信は基本的に、私がここに書いたことの要約です:ユニットテストは嘘をつきます

于 2011-10-24T13:05:37.817 に答える
64

単体テストを作成するときは、依存関係をモックすることで、テスト対象のコードの範囲を現在作成中のクラスに限定します。Sentence クラスを作成していて、Sentence が Word に依存している場合は、モック Word を使用します。Word をモックすることで、そのインターフェイスだけに集中し、Sentence クラスが Word のインターフェイスとやり取りするときのさまざまな動作をテストできます。このようにして、私は Sentence の動作と実装をテストしているだけで、同時に Word の実装をテストしていません。

Word のインターフェイスに基づいて Word と対話するときに Sentence が正しく動作することを確認する単体テストを作成したら、統合テストを作成して、対話に関する私の仮定が正しいことを確認します。このために、実際のオブジェクトを提供し、最終的に Sentence と Word の両方を使用する機能を実行するテストを作成します。

于 2008-09-01T19:33:42.823 に答える
47

私の10ビット:D

ユニットテスト個々のコンポーネントのテストであると常に言われていました。これは最大限に実行する必要があります。現在、ほとんどのコンポーネントは小さな部品でできているため、これには多くのレベルがある傾向があります。私にとって、ユニットはシステムの機能的な部分です。したがって、何か価値のあるものを提供する必要があります(つまり、文字列解析のメソッドではなく、おそらくHtmlSanitizer)。

統合テストは次のステップであり、1つ以上のコンポーネントを取得し、それらが正常に連携することを確認します。コンポーネントが個別にどのように機能するかについての複雑な心配はありませんが、HTMLをHtmlEditControlに入力するとどういうわけか魔法のようにその有効かどうかを知っています。

それは本当の可動線ですが..私はむしろ、いまいましいコードを終止符で動作させることにもっと焦点を合わせたいと思います^ _ ^

于 2008-08-14T08:59:28.557 に答える
23

単体テストはモックを使用します

あなたが話しているのは、システムの統合全体を実際にテストする統合テストです。ただし、単体テストを行うときは、実際には各ユニットを個別にテストする必要があります。他のすべては嘲笑されるべきです。したがって、クラスの場合、Sentenceクラスを使用する場合、クラスWordWordモックする必要があります。Sentenceこの方法では、クラスの機能のみをテストします。

于 2009-08-03T17:07:18.523 に答える
18

統合テストについて考え始めると、論理レイヤーではなく物理レイヤーのクロスについて話していると思います。

たとえば、テストがコンテンツの生成に関係している場合、それは単体テストです。テストがディスクへの書き込みだけに関係している場合でも、それは単体テストですが、I/O とファイルのコンテンツの両方をテストすると、次に、統合テストを行います。サービス内で関数の出力をテストする場合、それは単体テストですが、サービスを呼び出して関数の結果が同じかどうかを確認すると、それが統合テストになります。

技術的には、とにかく1つのクラスだけを単体テストすることはできません。クラスが他のいくつかのクラスで構成されている場合はどうなりますか? それは自動的に統合テストになりますか? 私はそうは思わない。

于 2008-08-14T06:34:05.853 に答える
14

単一責任設計、その白黒を使用します。複数の責任、その統合テスト。

ダック テスト (ルックス、クワック、ワドル、アヒル) では、1 つ以上の新しいオブジェクトを含む単なる単体テストです。

コントローラーにはモデル ユニットとビュー ユニットの両方が含まれているため、mvc に入ってテストする場合、コントローラー テストは常に統合されます。そのモデルでロジックをテストすることを、単体テストと呼びます。

于 2008-08-14T06:32:30.317 に答える
4

統合テスト: データベースの永続性がテストされます。
単体テスト: データベース アクセスがモックされます。コード メソッドがテストされます。

于 2012-07-13T18:56:23.410 に答える
4

class1 の単体テストが class1 の機能をテストし、class2 の単体テストがその機能をテストし、データベースにアクセスしていない場合、相互作用するいくつかのクラスを単体テストと呼ぶと思います。

テストがスタックの大部分を通過し、データベースにヒットすることさえある場合、そのテストを統合テストと呼びます。

私はこの質問がとても好きです。なぜなら、TDD の議論は私には少し純粋すぎると感じることがあるからです。具体的な例を見るのは私にとって良いことです。

于 2008-08-14T06:37:17.407 に答える
4

私も同じことをします - 私はそれらをすべて単体テストと呼びますが、ある時点で、非常に多くのことをカバーする「単体テスト」があり、しばしば「..IntegrationTest」に名前を変更します - 名前の変更のみで、他は何も変更しません。

「アトミック テスト」(1 つの小さなクラスまたはメソッドのテスト) から、単体テスト (クラス レベル) と統合テスト、そして機能テスト (通常はトップダウンでより多くのものをカバーする) への継続があると思います。 - きれいなカットオフはないようです。

テストがデータを設定し、おそらくデータベース/ファイルなどをロードする場合、おそらく統合テストのほうが多いでしょう(統合テストでは、モックの使用が少なく、より実際のクラスが使用されていることがわかりますが、それはいくつかのモックを作成できないという意味ではありませんシステムの)。

于 2008-08-14T06:47:54.093 に答える
4

単体テストは、ソース コードの個々の単位が適切に機能していることを検証するテスト方法です。

統合テストは、個々のソフトウェア モジュールを組み合わせてグループとしてテストするソフトウェア テストのフェーズです。

ウィキペディアでは、ユニットをアプリケーションのテスト可能な最小部分として定義しています。これは、Java/C# ではメソッドです。しかし、Word と Sentence クラスの例では、文のクラスをテストするためにモックの単語クラスを使用するのはやり過ぎだと思うので、おそらく文のテストを書くだけです。したがって、文は私の単位であり、単語はその単位の実装の詳細です。

于 2008-08-14T10:26:18.613 に答える
3

単体テストは、必要に応じて、作業単位またはコード ブロックに対してテストします。通常、1 人の開発者によって実行されます。

統合テストとは、開発者がコードをソース管理リポジトリにコミットするときに、できれば統合サーバーで実行されるテストを指します。統合テストは、Cruise Control などのユーティリティによって実行される場合があります。

したがって、単体テストを行って、構築した作業単位が機能していることを検証します。次に、統合テストで、リポジトリに追加したものが他の何かを壊していないことを検証します。

于 2008-08-14T06:36:58.140 に答える
2

クラスをホワイト ボックス テストするテストを単体テストと呼びます。クラスが必要とする依存関係はすべて、偽物 (モック) に置き換えられます。

統合テストは、複数のクラスとそれらの相互作用が同時にテストされるテストです。これらの場合、一部の依存関係のみが偽造/モックされます。

依存関係の 1 つが実際のもの (つまり、偽造されていない) でない限り (IFormsAuthentication など)、Controller の統合テストを呼び出しません。

2 種類のテストを分離すると、システムを異なるレベルでテストする場合に役立ちます。また、統合テストは長寿命になる傾向があり、単体テストは迅速に実行されるはずです。実行速度の違いは、それらが異なる方法で実行されることを意味します。私たちの開発プロセスでは、単体テストはチェックイン時に実行され (非常に高速なので問題ありません)、統合テストは 1 日に 1 回または 2 回実行されます。私はできるだけ頻繁に統合テストを実行しようとしますが、通常はデータベースへのアクセス/ファイルへの書き込み/rpc の作成/etc が遅くなります。

これにより、別の重要なポイントが発生します。単体テストでは、IO (ディスク、ネットワーク、データベースなど) にヒットしないようにする必要があります。そうしないと、速度が大幅に低下します。これらの IO 依存関係を設計するには、少し手間がかかります。「単体テストは高速でなければならない」というルールに忠実であったとは言えませんが、そうであれば、はるかに大規模なシステムでの利点がすぐに明らかになります。 .

于 2008-08-14T12:19:55.603 に答える
2

類推による簡単な説明

上記の例は非常にうまく機能するので、繰り返す必要はありません。そのため、理解を助けるために例を使用することに焦点を当てます。

統合テスト

統合テストでは、すべてが連携しているかどうかを確認します。一連の歯車が一緒に働く時計を想像してみてください。統合テストは次のようになります: 時計は正しい時間を伝えていますか? 3日後でも正確な時刻を示していますか?

それがあなたに伝えるのは、全体的な作品が機能しているかどうかだけです. 失敗した場合: どこで失敗したのか正確にはわかりません。

単体テスト

これらは本当に特定の種類のテストです。ある特定のことが機能しているか失敗しているかを示します。このタイプのテストの鍵は、他のすべてが正常に機能していると仮定して、特定の 1 つだけをテストすることです。それが重要なポイントです。

例: 例 を使用して、この点について詳しく説明しましょう。

  • 車を例に考えてみましょう。
  • 車の統合テスト: たとえば、車は Woop Woop まで行き来しますか? これができれば、車は全体的に機能していると言えます。統合テストです。故障した場合、実際に故障している場所がわかりません。ラジエーター、トランスミッション、エンジン、またはキャブレターですか? あなたは何もわかってない。それは何でもかまいません。
  • 車の単体テスト: エンジンは動いているか? このテストは、車内の他のすべてが正常に機能していることを前提としています。そうすれば、この特定の単体テストが失敗した場合でも、問題がエンジンにあることを確信できます。そのため、問題を迅速に切り分けて修正できます。

スタブの使用

  • 車の統合テストが失敗したとします。Echuca へのドライブがうまくいきません。問題はどこだ?

  • ここで、あなたのエンジンが特殊な燃料噴射システムを使用しており、このエンジン ユニット テストも失敗したとします。つまり、結合テストとエンジン単体テストの両方が失敗しました。ではどこに問題があるのでしょうか。(答えが出るまで 10 秒かかります。)

  • エンジンの問題ですか、それとも燃料噴射システムの問題ですか?

ここで問題がわかりますか?何が失敗しているのか正確にはわかりません。異なる外部依存関係を使用する場合、これら 10 のすべての依存関係が問題を引き起こしている可能性があり、どこから始めればよいかわかりません。そのため、単体テストではスタブを使用して、他のすべてが正常に機能していることを前提としています。

于 2016-12-06T00:58:19.397 に答える
1

この質問は少しアカデミックですね。;-) 私の見解: 私にとって、統合テストは全体のテストであり、10 の部分のうち 2 つの部分が一緒になっているかどうかではありません。私たちの統合テストは、マスター ビルド (40 個のプロジェクトを含む) が成功するかどうかを示しています。プロジェクトには、大量の単体テストがあります。私にとって単体テストに関して最も重要なことは、ある単体テストが別の単体テストに依存してはならないということです。したがって、私にとって、上記の両方のテストは、独立している場合、単体テストです。統合テストでは、これは重要である必要はありません。

于 2008-08-14T06:37:59.870 に答える
1

これらのテストは、これら 2 つのクラスの統合をテストするようになったため、本質的に統合テストになりましたか? それとも、2 つのクラスにまたがる単なる単体テストですか?

私はイエスとイエスだと思います。2 つのクラスにまたがる単体テストが統合テストになりました。

システムのこれらの部分が異なる開発者によって実装されるのに十分な大きさである場合、これは重要です。その場合、Word は単独で単体テストされ、Sentence は MockWord を使用して単体テストされ、次に Sentence は Word との統合テストが行​​われます。

実際の違いの例は次のとおりです。1) 1,000,000 要素の配列は簡単に単体テストされ、正常に動作します。2) BubbleSort は、10 要素のモック配列で簡単に単体テストされ、正常に動作します。 3) 統合テストは、何かがあまり良くないことを示しています。

これらの部分が 1 人で開発された場合、開発者が既に実数配列を持っていて、モック実装を必要としないという理由だけで、BubbleSoft の単体テスト中に問題が見つかる可能性が最も高くなります。

于 2008-09-25T09:37:29.267 に答える
1

さらに、単体テストと統合テストの両方を自動化し、JUnit などを使用して記述できることを覚えておくことが重要です。JUnit 統合テストでは、このorg.junit.Assumeクラスを使用して、環境要素 (データベース接続など) の可用性やその他の条件をテストできます。

于 2013-09-10T17:12:33.200 に答える
0

あなたが TDD の純粋主義者なら、本番コードを書く前にテストを書きます。もちろん、テストはコンパイルされないので、最初にテストをコンパイルしてから、テストをパスさせます。

単体テストではこれを行うことができますが、統合テストや受け入れテストではできません。統合テストを試みた場合、終了するまで何もコンパイルされません!

于 2018-11-02T17:08:54.510 に答える