web-dev-qa-db-ja.com

MockitoとJMockitの比較-なぜMockitoはJMockitよりも優れているのですか?

私は自分のプロジェクトにどのモックフレームワークを使用するかを調査しており、それを JMockitMockito に絞り込んでいます。

StackoverflowでMockitoが「 Javaに最適なモックフレームワーク 」に投票されたことに気付きました。
JMockitの「 モッキングツール比較マトリックス 」の機能を比較すると、JMockitには複数の異なる機能があります。

Mockitoで何ができるのかJMockitでは達成できない特定の情報(意見ではない) およびその逆?

118
user63904

競争はJMockitPowerMockの間で、そしてMockito

プロキシとCGLIBのみを使用し、新しいフレームワークのようなJava 5インスツルメンテーションを使用しないため、「プレーン」なjMockとEasyMockはそのままにしておきます。

また、jMockには4年以上安定したリリースがありませんでした。 jMock 2.6.0では、RC1からRC2に移行するのに2年かかり、実際にリリースされるまでさらに2年かかりました。

プロキシとCGLIBとインスツルメンテーションについて:

(EasyMockおよびjMock)はJava.lang.reflect.Proxyに基づいており、これにはインターフェースの実装が必要です。さらに、CGLIBサブクラスの生成を通じて、クラスのモックオブジェクトの作成をサポートします。そのため、上記のクラスをfinalにすることはできず、オーバーライド可能なインスタンスメソッドのみをモックできます。ただし、最も重要なのは、これらのツールを使用する場合、テスト対象コード(つまり、テスト対象の特定のクラスが依存する他のクラスのオブジェクト)の依存関係をテストで制御し、モックインスタンスをクライアントに渡す必要があることですそれらの依存関係。したがって、単体テストを作成するクライアントクラスのnew演算子を使用して、依存関係を単純にインスタンス化することはできません。

最終的に、従来のモッキングツールの技術的な制限により、製品コードに次の設計上の制限が課されます。

  1. テストでモックする必要のある各クラスは、個別のインターフェイスを実装するか、最終クラスではない必要があります。
  2. テストする各クラスの依存関係は、構成可能なインスタンス作成メソッド(工場またはサービスロケーター)から取得するか、依存関係の注入のために公開する必要があります。そうしないと、単体テストは依存関係の模擬実装をテスト対象のユニットに渡すことができません。
  3. 模擬できるのはインスタンスメソッドのみであるため、単体テスト対象のクラスは、依存関係にある静的メソッドを呼び出すことも、コンストラクターを使用してインスタンス化することもできません。

上記は http://jmockit.org/about.html からコピーされます。さらに、いくつかの方法で自身(JMockit)、PowerMock、およびMockitoを比較します。

Javaのためのその他のモック作成ツールもあります。これは、PowerMock、jEasyTest、およびMockInjectの間で従来の制限も克服します。JMockitの機能セットに最も近いのはPowerMockです。そのため、ここで簡単に評価します(他の2つはより限定されており、もう積極的に開発されていないようです)。

JMockitとPowerMock

  • まず第一に、PowerMockはモック用の完全なAPIを提供するのではなく、現在EasyMockまたはMockitoである別のツールの拡張機能として機能します。これは、これらのツールの既存ユーザーにとって明らかに利点です。
  • 一方、JMockitはまったく新しいAPIを提供しますが、メインAPI(期待)はEasyMockとjMockの両方に似ています。これにより学習曲線が長くなりますが、JMockitはよりシンプルで一貫性のある使いやすいAPIを提供できます。
  • JMockit Expectations APIと比較して、PowerMock APIはより「低レベル」であり、ユーザーはテストの準備が必要なクラスを把握し、指定する必要があります(@PrepareForTest({ClassA.class、...})アノテーション)およびプロダクションコードに存在する可能性のあるさまざまな種類の言語構造を処理するために特定のAPI呼び出しが必要です:静的メソッド(mockStatic(ClassA.class))、コンストラクター(suppress(constructor(ClassXyz.class)))、コンストラクター呼び出し( expectNew(AClass.class))、部分モック(createPartialMock(ClassX.class、 "methodToMock"))など。
  • JMockit Expectationsでは、あらゆる種類のメソッドとコンストラクターが純粋に宣言的な方法でモックされます。@ Mockedアノテーションの正規表現を使用して、または記録された期待なしにメンバーを単に「モック解除」することにより、部分モッキングが指定されます。つまり、開発者は、テストクラスの共有「モックフィールド」、または個々のテストメソッドの「ローカルモックフィールド」および/または「モックパラメータ」を宣言するだけです(この最後のケースでは、@ Mockedアノテーションはしばしば必要とされる)。
  • EqualsやhashCodeのモックのサポート、オーバーライドされたメソッドなど、JMockitで利用可能な機能の一部は、現在PowerMockではサポートされていません。また、テストコード自体が実際の実装クラスの知識を持たずに、テストの実行時に指定された基本型のインスタンスおよびモック実装をキャプチャするJMockitの機能に相当するものはありません。
  • PowerMockは、モッククラスの修正バージョンを生成するために、カスタムクラスローダー(通常はテストクラスごとに1つ)を使用します。カスタムクラスローダーをこのように頻繁に使用すると、サードパーティのライブラリと競合する可能性があるため、テストクラスで@PowerMockIgnore( "package.to.be.ignored")アノテーションを使用する必要がある場合があります。
  • JMockitで使用されるメカニズム(「Javaエージェント」によるランタイムインスツルメンテーション)は、JDK 1.5で開発するときに「-javaagent」パラメーターをJVMに渡す必要がありますが、よりシンプルで安全です。 JMockitはAttachを使用してオンデマンドでJavaエージェントを透過的にロードできるため、JDK 1.6+(古いバージョンにデプロイする場合でも常に開発に使用できます)ではこのような要件はありませんAPI。

もう1つの最近のモッキングツールはMockitoです。古いツール(jMock、EasyMock)の制限を克服しようとはしませんが、モックを使用した新しいスタイルの動作テストを導入します。 JMockitは、検証APIを介してこの代替スタイルもサポートしています。

JMockit対Mockito

  • Mockitoは、レコード(when(...))フェーズと検証(verify(...))フェーズとの間でコードを分離するために、APIへの明示的な呼び出しに依存しています。つまり、テストコードでモックオブジェクトを呼び出すには、モックAPIの呼び出しも必要になります。さらに、これはしばしばwhen(...)およびverify(mock)...呼び出しの繰り返しにつながります。
  • JMockitでは、同様の呼び出しは存在しません。確かに、新しいNonStrictExpectations()および新しいVerifications()コンストラクター呼び出しがありますが、それらはテストごとに(通常)一度だけ発生し、モックされたメソッドおよびコンストラクターへの呼び出しとは完全に分離されます。
  • Mockito APIには、模擬メソッドの呼び出しに使用される構文にいくつかの矛盾が含まれています。レコードフェーズでは、when(mock.mockedMethod(args))...のような呼び出しがありますが、検証フェーズでは、この同じ呼び出しがverify(mock).mockedMethod(args)として記述されます。最初のケースではmockedMethodの呼び出しがモックオブジェクト上で直接行われ、2番目のケースではverify(mock)によって返されたオブジェクト上で行われます。
  • モックされたメソッドへの呼び出しは常にモックされたインスタンス自体で直接行われるため、JMockitにはこのような矛盾はありません。 (1つだけ例外があります:同じ模擬インスタンスでの呼び出しに一致するために、onInstance(mock)呼び出しが使用され、onInstance(mock).mockedMethod(args)のようなコードになります。ただし、ほとんどのテストではこれを使用する必要はありません) )
  • メソッドの連鎖/ラップに依存する他のモック作成ツールと同様に、Mockitoはvoidメソッドをスタブ化するときに一貫性のない構文に遭遇します。たとえば、when(mockedList.get(1))。thenThrow(new RuntimeException());と記述します。非voidメソッドの場合、およびdoThrow(new RuntimeException())。when(mockedList).clear();無効なもの。 JMockitでは、常に同じ構文です:mockedList.clear(); result = new RuntimeException();。
  • さらに別の矛盾がMockitoスパイの使用で発生します。「モック」は、スパイされたインスタンスで実際のメソッドを実行できるようにします。たとえば、spyが空のリストを参照する場合、when(spy.get(0))。thenReturn( "foo")を記述する代わりに、doReturn( "foo")。when(spy).get( 0)。 JMockitでは、動的モック機能はスパイと同様の機能を提供しますが、実際のメソッドは再生段階でのみ実行されるため、この問題はありません。
  • Javaの最初のモックAPIであるEasyMockおよびjMockでは、(デフォルトで)予期しない呼び出しを許可しないモックオブジェクトの、モックされたメソッドの予想される呼び出しの記録に焦点が当てられていました。これらのAPIは、予期しない呼び出しを許可するモックオブジェクトの許可された呼び出しの記録も提供しますが、これはセカンドクラスの機能として扱われました。さらに、これらのツールでは、テスト対象のコードが実行された後、モックへの呼び出しを明示的に検証する方法はありません。そのような検証はすべて、暗黙的かつ自動的に実行されます。
  • Mockito(およびUnitils Mock)では、反対の視点が取られています。記録されているかどうかにかかわらず、テスト中に発生する可能性のあるモックオブジェクトへのすべての呼び出しは許可され、予期されません。検証は、テスト対象のコードが実行された後に明示的に実行され、自動的には実行されません。
  • どちらのアプローチも極端すぎるため、最適ではありません。 JMockit Expectations&Verificationsは、開発者がテストごとに厳密な(デフォルトで予期される)モック呼び出しと非厳密な(デフォルトで許可される)モック呼び出しの最適な組み合わせをシームレスに選択できる唯一のAPIです。
  • より明確にするために、Mockito APIには次の欠点があります。テスト中に非voidモックメソッドの呼び出しが発生したことを確認する必要があるが、テストでは戻り型のデフォルトとは異なるそのメソッドからの戻り値が必要な場合、Mockitoテストには重複したコードが含まれます。記録段階ではwhen(mock.someMethod())。thenReturn(xyz)呼び出し、検証段階ではverify(mock).someMethod()を呼び出します。 JMockitを使用すると、厳密な期待値を常に記録することができ、明示的に検証する必要はありません。または、記録された非厳密な期待に対して呼び出し回数制約(回= 1)を指定できます(Mockitoでは、このような制約はverify(mock、constraint)呼び出しでのみ指定できます)。
  • Mockitoには、順序どおりの検証、および完全な検証(つまり、モックオブジェクトへのすべての呼び出しが明示的に検証されていることの確認)の構文が貧弱です。最初のケースでは、追加のオブジェクトを作成し、それを検証するための呼び出しを行う必要があります:InOrder inOrder = inOrder(mock1、mock2、...)。 2番目のケースでは、verifyNoMoreInteractions(mock)またはverifyZeroInteractions(mock1、mock2)などの呼び出しを行う必要があります。
  • JMockitを使用すると、新しいVerifications()(または両方の要件を組み合わせる新しいFullVerificationsInOrder())の代わりに、新しいVerificationsInOrder()または新しいFullVerifications()を記述するだけです。関係するモックオブジェクトを指定する必要はありません。余分なモックAPI呼び出しはありません。また、ボーナスとして、順序付けられた検証ブロック内でunverifiedInvocations()を呼び出すことにより、Mockitoでは単純に不可能な順序関連の検証を実行できます。

最後に、JMockit Testing Toolkitには、完全で洗練された開発者テストソリューションを提供するために、他のモッキングツールキットよりも広いスコープおよびより野心的な目標があります。人為的な制限がなくても、モック用の優れたAPIは、テストの生産的な作成には不十分です。 IDEに依存せず、使いやすく、よく統合されたコードカバレッジツールも不可欠であり、それがJMockitカバレッジの提供を目指しています。開発者テストツールセットのもう1つの部分は、テストスイートのサイズが大きくなるにつれてより便利になります。これは、プロダクションコードへのローカライズされた変更後にテストを段階的に再実行する機能です。これは、カバレッジツールにも含まれています。

(確かに、ソースは偏っている可能性がありますが...

私はJMockitで行くと言います。最も使いやすく、柔軟性があり、テストするクラスを制御できない場合(または互換性の理由などにより壊れない場合)は、難しいケースやシナリオを含め、ほとんどすべてのケースで機能します。

JMockitでの私の経験は非常に前向きです。

136
Hendy Irawan

私はMockitoとJMockitの両方で働いていましたが、私の経験は次のとおりです。

  • モッキート:

    • 暗黙のモック(->使いやすさは向上しましたが、モックで許可されていないメソッド呼び出しを検出できない可能性があります)
    • 明示的な検証
  • EasyMock:

    • 明白なm笑
    • 暗黙的な検証
  • JMockit:

    • 両方をサポート
  • さらに、JMockitのその他の利点:

    • 静的メソッド/コンストラクターなどをモックしている場合(UTなしで非常に古いレガシーコードベースを拡張する場合など)、次の2つの選択肢があります。1)Powermock拡張付きMockito/EasyMockまたは2)Jmockit
    • 組み込みカバレッジレポート

私は個人的にはJMockitを好みます。JMockitは機能が豊富で柔軟性が高いと思いますが、少し急な学習曲線が必要です。通常、同じモック効果を実現するには複数の方法があり、モックを設計するときはさらに注意が必要です。

23
Tumer

私はjMockitonlyを使用します。Deencapsultation.classのリフレクションライブラリだからです。私は実際にMockitoのスタイルが大好きですが、コードの変更を拒否し、限られたテストフレームワークがそれを実現できるようにAPIを濁らせています。そして、私はすべてのコードをテストするのが大好きなので、プライベートメソッドを簡単にテストできないフレームワークは使用したくないものです。

この記事 に揺れた

(確かに大きな)学習曲線の後、jMockitは現在、私のモックのメインのユニットテストフレームワークです。

15
Joseph Erickson

従来のコードベース(多くの静的メソッド呼び出しなど)を簡単にテストするために、JMockitは非常に貴重です。 [私のブログの 記事 の恥知らずなプラグイン]

4
Jeff Olson

個人的には EasyMock を好みます。
ニース、通常、および厳密なモックコントロールを切り替える機能は、私のお気に入りの機能の1つです。

0
Bivas