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


124

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

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

誰もが何に関する具体的な情報(ない意見)持っていますMockitoを用いて達成することができない行うことができますJMockitその逆と副の?


2
おそらくmockitoの使いやすさはおそらく良いですが、JMockitはMockitoよりも成熟しているとは思いません...
アロイスコチャード

42
投票数から判断すると、明らかに、この質問に対する答えはコミュニティによって非常に求められています。つまり、この質問をクローズさせたこのサイトの直交化戦略には、いくつかの深刻な再考が必要です。ツリーのグラフ分析では、ノードの数と同じくらい多くの方法でツリーの直交性を表示することを認識していません。おそらく、問題ではなく、このサイトの直交性が不適切です。
Blessed Geek

9
終了しない場合は+1。これらの答えには価値があります。テクノロジーの選択は簡単ではなく、これらの質問は多くの時間を節約できます。確かに正しい答えはないかもしれませんが、StackOverflowは答えがなくても質問に対応する必要があります。
mhstnsc

6
これを「建設的ではない」ものとして閉じるのはばかげていると述べている人たちに、私のサポートを追加します。ここで提供された回答は、「事実、参考文献、および/または専門知識」によってサポートされました。一部の「討論、投票、または拡張ディスカッション」を要求しないテクノロジの分野での質問は、通常、尋ねる価値はほとんどありません。さらに、事実と専門知識を提供することは、さまざまな経験に依存します。これらの違いは、議論と長い議論につながります。
Jeff Nyman

@Alois-JMockitがMockitoよりも成熟していないように見える具体的な例を挙げられますか?
NitinS 2016

回答:


140

更新2019年9月:唯一の春ブーツで(デフォルトで)サポートモックフレームワークがあるMockito。Springを使用する場合、答えは明白です。


競争はJMockitPowerMockの間、そしてMockitoの思います。

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

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をいくつかの方法で比較します。

これで、PowerMock、jEasyTest、MockInjectなど、従来のツールの制限を克服するJava用のモッキングツールが他にもあります。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 APIを使用してオンデマンドでJavaエージェントを透過的にロードできるため、JDK 1.6+(古いバージョンにデプロイする場合でも、常に開発に使用できます)ではこのような要件はありません。

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

JMockit対Mockito

  • Mockitoは、APIへの明示的な呼び出しに依存して、レコード(when(...))フェーズと検証(verify(...))フェーズの間でコードを分離します。つまり、テストコードでモックオブジェクトを呼び出す場合も、モックAPIを呼び出す必要があります。さらに、これは多くの場合、when(...)およびverify(mock)...呼び出しの反復につながります。
  • JMockitでは、同様の呼び出しは存在しません。もちろん、新しいNonStrictExpectations()および新しいVerifications()コンストラクター呼び出しがありますが、これらはテストごとに(通常)1回だけ発生し、モックされたメソッドおよびコンストラクターの呼び出しとは完全に分離されています。
  • 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では、動的モッキング機能はスパイと同様の機能を提供しますが、実際のメソッドは再生フェーズでのみ実行されるため、この問題はありません。
  • EasyMockおよびjMock(Javaの最初のモックAPI)では、(デフォルトで)予期しない呼び出しを許可しないモックオブジェクトに対して、モックメソッドの予想される呼び出しの記録に完全に重点が置かれていました。これらの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テストツールキットにはあり、より広い範囲、より野心的な目標を完全かつ洗練された開発者のテスト・ソリューションを提供するために、他のモックツールキットよりを。モック用の優れたAPIは、人為的な制限がなくても、テストを生産的に作成するには不十分です。IDEに依存せず、使いやすく、よく統合されたコードカバレッジツールも不可欠です。これが、JMockitカバレッジが提供することを目指しています。テストスイートのサイズが大きくなるにつれて、さらに役立つ開発者テストツールセットのもう1つの部分は、本番用コードへのローカライズされた変更後にテストを段階的に再実行する機能です。これは、カバレッジツールにも含まれています。

(確かに、ソースには偏りがあるかもしれませんが、まあ...)

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

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


1
私はjmockitを使用したことがありませんが、ディスカッションに別の引数を追加したいと思います。すべてのディスカッションされたフレームワークのGoogleトレンド比較を見てください。2012年6月6日の時点で、JMockitは、MockitoおよびEasyMockと比較した場合、Googleトレンドグラフに表示されません。また、フレームワークを選択する際には、ユーザー数も重要です。
機械

3
それはかなり奇妙です。MockitoとJMockItは、Googleでそれぞれ409 'ヒットと83'ヒットを提供します。確かに、JMockItは少なくとも表示されるはずです。
thoredge

5
あなたの答えはとても役に立ちます。私は単にMockitoを使用することを計画しましたが、今度はJMockitを最初にテストします。試さない方がいいようです。@機械:はい、傾向を確認することは重要ですが、主な基準が主流にあなたを制限し、革新からあなたを保護するので、それを選択することは重要です。
デーモン2013年

1
私はこれが古いスレッドであることを知っていますが、このレビューを読んだ後、私も試してみようと思いました。表面的には、JMockitは非常に有望です。しかし、これまでのところ、コミュニティによるサポートが非常に不足していることがわかりました。Mock APIの理解に大きな問題があり、問題を投稿した後、2日間応答がありませんでした。
エリックB.

1
答えは8年前なので、答えの中の多くの点が正しくありません。1つのポイントは-javaagent、Java 9以降では自己接続できず、適切な回避策を見つけることは明らかに開発者の範囲外だったため、JMockitには1.42以降のフラグが必要です。もう1つのポイントは、JMockitがプライベートメソッドとコンストラクターをモックすることを許可しない一方で、PowerMockがフェイクを行うことです。
ヴァンパイア

24

私はMockitoとJMockitの両方を使用しましたが、それらの経験は次のとおりです。

  • モッキート:

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

    • あざける
    • 暗黙の検証
  • JMockit:

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

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

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


そこにあるstackoverflow.com/questions/8003278/...「verifyNoMoreInteractionsは、」あなたはmockitoと擬似明示的なモックをしたい場合は、私が思う
rogerdpack

15

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

この記事に心を揺さぶられました

(確かに大規模な)学習曲線の後、jMockitはモックの私の主要な単体テストフレームワークになりました。


7
おそらく、プライベートメソッドをテストする必要があると思われる場合は、コードの機能(実際のポイントであり、パブリックメソッドを実行することで判断できます)ではなく、コードの動作にあまりにも関心があります。また、その記事を読みたいのですが、リンクが切れています。
コードボックス2013

4年後も、jMockitを主要なテストフレームワークとして使用していますか?初めて試してみて、いくつかの問題が発生していますが、jMockitの仕組みを誤解しているか、それとも存在しない機能なのかはわかりません。
エリックB.

jMockitはプライベートメソッドのテストをサポートしなくなりました。Deencapsulationクラスは徐々に非推奨になり、バージョン1.47では完全に削除されました。jmockit.github.io/changes.html
Pytry

4

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


0

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.