3つの目的でjUnitテストケースを作成します。
Mockito.verify()
を使用する理由と時期がわかりません。 verify()
が呼び出されているのを見ると、jUnitが実装を認識し始めていることがわかります。 (したがって、機能が影響を受けていなくても、実装を変更するとjUnitが破損します)。
を探しています:
Mockito.verify()
を適切に使用するためのガイドラインは何ですか?
JUnitsがテスト対象クラスの実装を認識している、または密接に結合しているのは基本的に正しいですか?
クラスAのコントラクトに、タイプCのオブジェクトのメソッドBを呼び出すという事実が含まれている場合、タイプCのモックを作成し、メソッドBが呼び出されたことを確認してテストする必要があります。
これは、クラスAのコントラクトが、タイプC(インターフェースまたはクラスである可能性がある)について説明するのに十分な詳細を持っていることを意味します。そうです、私たちは単に「システム要件」を超えて、実装を説明するための何らかの方法に進む仕様のレベルについて話しているのです。
これは単体テストでは正常です。ユニットテストを行う場合、各ユニットが「正しいこと」を行っていることを確認する必要があります。これには通常、他のユニットとの相互作用が含まれます。ここでいう「ユニット」とは、クラス、またはアプリケーションのより大きなサブセットを意味する場合があります。
更新:
これは検証だけでなく、スタブにも当てはまると思います。コラボレータークラスのメソッドをスタブ化するとすぐに、ユニットテストはある意味、実装に依存するようになります。そうなるのは、単体テストの性質のようなものです。 Mockitoは検証と同じくらいスタブに関するものであるため、Mockitoを使用しているという事実は、この種の依存関係を実行することを意味します。
私の経験では、クラスの実装を変更する場合、それに合わせてユニットテストの実装を変更する必要があります。ただし、通常、ユニットテストのインベントリを変更する必要はありませんareクラスに対して。もちろん、変更の理由は、以前にテストできなかった条件の存在でした。
これがユニットテストの目的です。コラボレータークラスの使用方法に対するこの種の依存関係の影響を受けないテストは、実際にはサブシステムテストまたは統合テストです。もちろん、これらも頻繁にJUnitで記述されており、しばしばモックの使用を伴います。私の意見では、「JUnit」はひどい名前で、すべての異なるタイプのテストを作成できる製品のことです。
デイビッドの答えはもちろん正しいのですが、なぜあなたがこれを望むのかを十分には説明していません。
基本的に、ユニットテストを行うときは、機能ユニットを単独でテストします。入力が期待される出力を生成するかどうかをテストします。時には、副作用もテストする必要があります。簡単に言うと、verifyを使用すると、それが可能になります。
たとえば、DAOを使用して物事を保存することになっているビットのビジネスロジックがあります。これを行うには、DAOをインスタンス化し、ビジネスロジックに接続し、データベースを調べて、予想されるものが保存されているかどうかを確認する統合テストを使用します。それはもう単体テストではありません。
または、DAOをモックして、期待どおりに呼び出されることを確認できます。 mockitoを使用すると、何かが呼び出されること、呼び出される頻度、およびパラメーターでマッチャーを使用して、特定の方法で呼び出されることを確認できます。
このような単体テストの裏側は、実際、テストを実装に結び付けているため、リファクタリングが少し難しくなります。一方、良いデザインの匂いは、適切に実行するために必要なコードの量です。テストを非常に長くする必要がある場合は、おそらく設計に何らかの問題があります。そのため、テストする必要がある多くの副作用/複雑な相互作用を伴うコードは、おそらく良いものではありません。
これは素晴らしい質問です!根本的な原因は次のとおりだと思います。ユニットテストだけでなく、JUnitを使用しています。したがって、質問を分割する必要があります。
ユニットテストよりも高いテストを無視する場合、質問は「Mockito.verifyでのwhite-boxユニットテストの使用」と言い換えることができます。 ()単体テストと実装の間に素晴らしいカップルを作成します。 "grey-box"単体テストとこれに使用する経験則」。
それでは、このすべてを段階的に見ていきましょう。
*-Mockito.verify()をintegration(または他の単体テストよりも高い)テストで使用する必要がありますか?*答えはもちろん、これにモックを使用するべきではありません。テストはできるだけ実際のアプリケーションに近いものにする必要があります。アプリケーションの孤立した部分ではなく、完全なユースケースをテストしています。
*black-boxvswhite-boxunit-testing*black-boxアプローチを使用している場合、実際に何をしているのかを指定します(すべての等価クラス)入力、state、および期待される出力を受け取ることをテストします。このアプローチでは、一般にモックを使用することは正当化されます(正しいことを実行していることを模倣するだけで、テストしたくない)が、Mockito.verify()を呼び出すことは不要です。
white-boxアプローチを実際に使用している場合は、behaviourをテストしていますあなたのユニットの。このアプローチでは、Mockito.verify()を呼び出すことが不可欠です。ユニットが期待どおりに動作することを確認する必要があります。
グレーボックステストの経験則ホワイトボックステストの問題は、高いカップリングを作成することです。可能な解決策の1つは、ホワイトボックステストではなく、グレーボックステストを実行することです。これは、白黒ボックステストの一種です。ホワイトボックスのテストのようにユニットの動作を実際にテストしていますが、一般的には実装に依存しません可能な場合。可能な場合は、ブラックボックスの場合と同様にチェックを行い、出力が予想どおりであることをアサートします。それで、あなたの質問の本質は、それが可能なときです。
これは本当に難しいです。良い例はありませんが、例を挙げましょう。 equals()とequalsIgnoreCase()を使用して上記で言及した場合、Mockito.verify()を呼び出して出力をアサートしないでください。できなかった場合は、できるまでコードを小さな単位に分解します。一方、@ Serviceがあり、本質的に@Serviceのラッパーである@ Web-Serviceを作成していると仮定します。これは、すべての呼び出しを@Serviceに委任します(さらにいくつかのエラー処理を行います)。この場合、Mockito.verify()の呼び出しは必須です。@ Seriveに対して行ったすべてのチェックを複製しないでください。正しいパラメーターメーターリストで@Serviceを呼び出していることを確認してください。
私はあなたが古典的なアプローチの観点から絶対に正しいと言わなければなりません:
普遍的なツールはないことを覚えておくことが重要です。ソフトウェアの種類、サイズ、会社の目標と市場の状況、チームのスキルなど、多くのことが、特定のケースで使用するアプローチの決定に影響します。
一部の人々が言ったように
リファクタリングの際にテストを壊すことについての懸念については、モック/スタブ/スパイを使用する場合にある程度予想されます。定義上ではなく、Mockitoなどの特定の実装に関するものではありません。しかし、このように考えることができます-メソッドの動作方法に大きな変更をもたらすリファクタリングを行う必要がある場合は、TDDアプローチで行うことをお勧めします。つまり、テストを変更できるということです最初は新しい動作(テストに失敗する)を定義し、thenは変更を行い、テストに再度合格します。