206

私は 3 つの目的で jUnit テスト ケースを作成します。

  1. 入力の組み合わせ/値のすべて (またはほとんど) で、コードが必要な機能をすべて満たしていることを確認します。
  2. 実装を変更できることを確認し、JUnit テスト ケースを使用して、すべての機能がまだ満足されていることを確認します。
  3. 私のコードが処理するすべてのユースケースのドキュメントとして、リファクタリングの仕様として機能します - コードを書き直す必要がある場合。(コードをリファクタリングし、jUnit テストが失敗した場合は、ユース ケースを見逃している可能性があります)。

なぜ、いつ使用する必要があるのか​​ わかりませんMockito.verify()。呼び出されているのを見るverify()と、jUnit が実装を認識していることがわかります。(したがって、実装を変更すると、機能に影響はありませんが、jUnits が壊れてしまいます)。

を探しています:

  1. を適切に使用するためのガイドラインは何Mockito.verify()ですか?

  2. jUnits がテスト対象のクラスの実装を認識する、または密結合することは根本的に正しいのでしょうか?

4

6 に答える 6

81

クラス A のコントラクトに、型 C のオブジェクトのメソッド B を呼び出すという事実が含まれている場合、型 C のモックを作成し、メソッド B が呼び出されたことを確認して、これをテストする必要があります。

これは、クラス A のコントラクトに、タイプ C (インターフェイスまたはクラスである可能性がある) について説明するのに十分な詳細があることを意味します。そうです、私たちが話しているのは、単なる「システム要件」を超えたレベルの仕様であり、実装を説明する方法です。

これは単体テストでは正常です。単体テストを行うときは、各ユニットが「正しいこと」を行っていることを確認する必要があります。これには、通常、他のユニットとの相互作用が含まれます。ここでの「ユニット」は、クラス、またはアプリケーションのより大きなサブセットを意味する場合があります。

アップデート:

これは検証だけでなく、スタビングにも当てはまると思います。共同作業者クラスのメソッドをスタブするとすぐに、単体テストはある意味で実装に依存するようになります。単体テストの性質上、そうです。Mockito は検証と同じくらいスタブに関するものであるため、Mockito を使用しているという事実は、この種の依存関係に出くわすことを意味します。

私の経験では、クラスの実装を変更すると、それに合わせて単体テストの実装を変更しなければならないことがよくあります。ただし、通常は、クラスの単体テストの一覧を変更する必要はありません。もちろん、変更の理由が以前にテストできなかった条件の存在であった場合を除きます。

これが単体テストの目的です。共同作業者クラスの使用方法に対するこの種の依存関係の影響を受けないテストは、実際にはサブシステム テストまたは統合テストです。もちろん、これらも JUnit で記述されることが多く、モックを使用することがよくあります。私の意見では、「JUnit」は、さまざまな種類のテストをすべて作成できる製品としてはひどい名前です。

于 2012-09-22T00:51:32.333 に答える
65

デビッドの答えはもちろん正しいですが、なぜこれが必要なのかを完全には説明していません。

基本的に、単体テストでは、機能の単位を分離してテストしています。入力が期待される出力を生成するかどうかをテストします。場合によっては、副作用もテストする必要があります。簡単に言えば、verify はそれを可能にします。

たとえば、DAO を使用して物事を格納することになっているビジネス ロジックが少しあります。これは、DAO をインスタンス化し、それをビジネス ロジックに接続し、データベースを調べて、期待されるものが保存されているかどうかを確認する統合テストを使用して行うことができます。それはもはや単体テストではありません。

または、DAO をモックして、期待どおりに呼び出されることを確認することもできます。mockito を使用すると、何かが呼び出されたこと、呼び出された頻度を確認できます。また、パラメーターにマッチャーを使用して、特定の方法で呼び出されることを確認することもできます。

このような単体テストの裏側は、テストを実装に結び付けているため、リファクタリングが少し難しくなります。一方、良いデザインの匂いは、それを適切に実行するのに必要なコードの量です。テストが非常に長くなる必要がある場合は、おそらく設計に問題があります。したがって、テストが必要な多くの副作用/複雑な相互作用を伴うコードは、おそらく良いことではありません。

于 2012-09-23T11:16:38.317 に答える
31

これは素晴らしい質問です!根本的な原因は、ユニットテストだけでなくJUnitを使用していることにあると思います。したがって、質問は分割する必要があります。

  • 統合(またはその他の単体テストよりも高度なテスト) テストで Mockito.verify() を使用する必要がありますか?
  • ブラックボックスの単体テストで Mockito.verify() を使用する必要がありますか?
  • ホワイトボックスの単体テストで Mockito.verify() を使用する必要がありますか?

したがって、単体テストよりも高いテストを無視する場合、質問は言い換えることできます単体テストと、これに使用する経験則」.

それでは、このすべてを段階的に見ていきましょう。

*-統合(または他の単体テストよりも高度なテスト) テストで Mockito.verify() を使用する必要がありますか?* 答えは明らかにノーだと思います。さらに、これにモックを使用するべきではありません。テストは、実際のアプリケーションにできるだけ近づける必要があります。アプリケーションの分離された部分ではなく、完全なユースケースをテストしています。

*ブラックボックスホワイトボックスのユニットテスト*ブラックボックスアプローチを使用している場合、実際に何をしているのか、(すべての等価クラス) 入力、状態、および期待される出力を受け取るテストを提供します。このアプローチでは、一般的にモックを使用することは正当化されます (モックが正しいことを行っていることを模倣するだけです。テストする必要はありません) が、Mockito.verify() の呼び出しは不要です。

ホワイトボックスアプローチを使用している場合、実際に行っていることは、ユニットの動作をテストしていることになります。このアプローチでは、Mockito.verify() の呼び出しが不可欠です。ユニットが期待どおりに動作することを確認する必要があります。

グレーボックステストの経験則 ホワイトボックステストの問題点は、結合度が高くなることです。考えられる解決策の 1 つは、ホワイト ボックス テストではなく、グレー ボックス テストを行うことです。これは、ブラックボックステストとホワイトボックステストを組み合わせたようなものです。ホワイト ボックス テストのようにユニットの動作を実際にテストしていますが、一般的には可能な場合は実装に依存しないようにします。可能であれば、ブラックボックスの場合のようにチェックを行い、出力が期待どおりであることをアサートします。したがって、あなたの質問の本質は、それが可能な場合です。

これは本当に大変です。良い例はありませんが、例を挙げてみましょう。上記の equals() と equalsIgnoreCase() の場合、Mockito.verify() を呼び出すべきではなく、出力をアサートするだけです。できなかった場合は、できるようになるまでコードを小さな単位に分解します。一方、@Service があり、@Service の基本的なラッパーである @Web-Service を書いているとします。これは、すべての呼び出しを @Service に委任します (そして、追加のエラー処理を行います)。この場合、Mockito.verify() の呼び出しが不可欠です。@Serive に対して行ったすべてのチェックを複製しないでください。正しいパラメーター リストを使用して @Service を呼び出していることを確認するだけで十分です。

于 2012-09-24T09:40:50.510 に答える
8

古典的なアプローチの観点からは、あなたは絶対に正しいと言わざるを得ません。

  • 最初にアプリケーションのビジネス ロジックを作成 (または変更)し、それをテスト (採用) でカバーする場合( Test-Last アプローチ)、ソフトウェアがどのように機能するかをテストに知らせるのは非常に苦痛で危険です。インプットとアウトプットのチェック。
  • テスト駆動型アプローチを実践している場合、テストは最初に記述され、変更され、ソフトウェアの機能のユース ケースを反映します。実装はテストに依存します。これは、ソフトウェアを特定の方法で実装する必要があることを意味する場合があります。たとえば、他のコンポーネントのメソッドに依存したり、特定の回数呼び出すことさえあります。そこでMockito.verify()が役に立ちます!

普遍的なツールはないことを覚えておくことが重要です。ソフトウェアの種類、規模、会社の目標と市場の状況、チームのスキル、その他多くの要因が、特定のケースでどのアプローチを使用するかの決定に影響します。

于 2015-03-30T15:16:23.243 に答える