ユニット テストと統合テストのいわゆる教科書的な定義は知っています。私が知りたいのは、ユニット テストをいつ記述するかということです... できるだけ多くのクラスのセットをカバーするように記述します。
たとえば、Word
クラスがある場合、そのクラスの単体テストをいくつか記述しますWord
。次に、Sentence
クラスの記述を開始し、クラスと対話する必要がある場合は、少なくとも対話する場所ではWord
両方をテストするように単体テストを記述することがよくあります。Sentence
Word
これらのテストは、これら 2 つのクラスの統合をテストするようになったため、本質的には統合テストになったのでしょうか、それとも 2 つのクラスにまたがる単なる単体テストなのでしょうか?
一般的に、この不確かな線のため、実際に統合テストを書くことはめったにありません... または、完成した製品を使用してすべての部分が正しく動作するかどうかを確認することが、実際の統合テストなのでしょうか。統合テストは手動で行われ、個々の機能の範囲を超えて繰り返されることはめったにありませんが。
私は統合テストを誤解しているのでしょうか、それとも統合テストと単体テストの間には実際にはほとんど違いがないのでしょうか?
ベストアンサー1
私にとっての主な違いは、統合テストでは、現実に近いシナリオでコードに負荷をかけるため、機能が動作しているか壊れているかが明らかになることです。統合テストでは、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 つのユニット テストだけです。
ここで、2つのシナリオを比較してみましょう。
同じバグによって、1 つのユニット テストだけが壊れます。
- 壊れた機能を使用しているすべての機能が
Log
赤くなっています - すべてのユニットテストは緑色ですが、ユニットテストのみが
Log
赤色です。
実際、壊れた機能を使用するすべてのモジュールの単体テストは、モックを使用することで依存関係が削除されたため、緑色になります。言い換えると、それらは理想的な、完全に架空の世界で実行されます。そして、これがバグを分離して探す唯一の方法です。単体テストとは、モックを作成することです。モックを作成しなければ、単体テストは行われません。
違い
統合テストは何が機能していないかを示します。しかし、問題がどこにあるのかを推測するのには役立ちません。
ユニット テストは、バグが正確にどこにあるのかを示す唯一のテストです。この情報を取得するには、他のすべての依存関係が正しく動作すると想定されるモック環境でメソッドを実行する必要があります。
そのため、「それとも、2 つのクラスにまたがる単体テストだけでしょうか」という文章は、どこかずれていると思います。単体テストは、2 つのクラスにまたがるべきではありません。
この返信は基本的に私がここに書いた内容の要約です:ユニットテストは嘘をつく、だから私はユニットテストが好きなのだ。