この記事では、Javaでモックを操作するための2つの一般的なライブラリーであるEasyMockとJMockの比較分析を行います。 JUnitの基本的な知識は理解に十分であり、この記事を読んだ後、これらのライブラリの両方を使用する方法について非常に良いアイデアを得ることができます。
問題のタスク
テストする必要があるものの例として、およそ次の構造を持つアプリケーションを検討します。 | |
- テストを実行するすべてのマシンからこのサーバーにアクセスできる必要があります。
- モックサーバーの動作の説明はコードの外部にあるため、特に1人の開発者がコードとサーバーでテストを更新し、もう1人の開発者が更新しない場合、さまざまなトラブルが発生する可能性があります。
テスト用の模擬サーバー(読むことができません)
| |
RequestHandler
インターフェイスを説明する
RequestHandler
インターフェイスを示しています( たとえば、アドレスhttp: // habrahabr .ru / blogs / java / 136466 /ターゲットはボールド/ blogs / java / 136466 /になります )。リクエスト本文でユーザーが送信したデータ。 2行目は、7行目から32行目
MockHttpServerHandler
クラスです。
RequestHandler
インストールされ、「ビジネスロジック」全体が委任され、その作業の結果がHTTP応答に記録されます。 3行目(36〜41行目)は
startServer
メソッドです。このメソッドは、アノテーションと名前から推測できるように、このクラスにリストされているテストが実行を開始してHTTPサーバーを開始する前に呼び出されます。
最初の最も簡単なテスト
理論的には、saveメソッドに隠されたコードがURL{serverAddress}/upload/{id}
を通過し、そこに
data
を渡すと仮定します。 これが実際に起こっているかどうかを確認してください。
ジョモック
| |
最初の行では、テストを実行するJMockコンテキストを作成する必要があります。 このコンテキストはテスト全体には十分ですが、それなしではできません 。 同じモックのいくつかの問題を回避するために、各テストの前にコンテキストを再作成する必要があります(つまり、
@Before
アノテーションでマークされたメソッド内)
@Before
行目では、インターフェイスのモックを簡単かつ自然に作成します。 次に、10〜13行目で、どの呼び出しが発生するかを説明します。 一見構文はあまり直感的ではありませんが、時間が経てば慣れます。 11行目では、引数
("/upload/" + id)
および
(data)
("/upload/" + id)
して
handle
メソッドを1回だけ呼び出すことを想定しています。 12行目では、最後の呼び出しが値
("Saved " + id)
を返すと言います。 ここでは、ご想像のとおり、 一般的なセキュリティはありません 。 誤って間違った型の値をそこに渡し、shlopotat例外を使用して、実行時にのみそれを知ることができます。 ただし、戻り値が重要でない場合、これをまったく記述できません。JMockは自動的にデフォルト値(
0
、
false
、
null
または空の文字列)を返します。 次に、新しく作成したモックハンドラーを使用し、テスト対象のアプリケーションを呼び出して、19行目ですべての予想される呼び出しが行われたことを確認する必要があることをモックサーバーに伝えます。 テストクラス
@RunWith(JMock.class)
アノテーション
@RunWith(JMock.class)
を追加することで、後者を取り除くことができます
イージーモック
| |
EasyMockでは、私の観点から、 予想される動作の仕様がより明確になっています。 ただし、このアプローチには欠点があります。11行目でわかるように、予想される動作の記録が終了したことを明示的に示す必要があります 。 すべての「ビジネスロジック」の後、17行目に進み、予想されるすべてのメソッドが呼び出されたことを確認します。 ちなみに、メソッドが何を返すかを気にしない場合、voidメソッドの場合は、
expect
コンストラクトを省略して、
requestHandler.handle("/upload/" + id, data)
呼び出すだけです。 さらに、
control
使用はオプションであり、簡単にこれを実行できます。
| |
メソッド呼び出しに対するより複雑な応答
ここで、外部コンポーネントに障害が発生したときにアプリケーションが正しく動作することをテストする必要があるとします。 これを行うには、
handle
メソッドで例外を整理するだけで十分です。その後、jettyはhttpステータス500自体を設定します。
ジョモック
| |
returnIterator
そのまま追加することもできますが、
Action
インターフェースを実装することで独自に調整することもできます。 確かに、それはあまり明確ではなく、ドキュメントはそれほど熱くありません 。
イージーモック
| |
| |
andThrow
加えて、
andThrow
使用することもでき
andDelegateTo
。これは、ご
andDelegateTo
、 メソッド呼び出しを他のオブジェクトに委任します ( コンパイル中に一般的なセキュリティはありません! )And
andAnswer
。 後者の場合、
IAnswer
インターフェイスを実装し、
answer
メソッド内にコードを記述する必要があります。 JMockよりも少し電力が少ないですが、はるかに便利です。
メソッドを呼び出すときの引数の一致
ここで、モックされたメソッドの呼び出しにどの引数を渡すべきか正確にはわからないとします。 唯一確実なことは、
target
引数にはどこかに
id
が含まれている必要があるということです。
ジョモック
| |
イージーモック
| |
呼び出し回数
ここで、条件を少し変更して、いくつかのメソッドを数回呼び出す必要があると言ってみましょう。 この例は現実からかなり遠ざかりましたが、単純なものを示すためにより重要なものを発明したくありません。ジョモック
| |
one
はそれだけではなく、予想される呼び出しの数を示していました。 必要なコールの数はすべてサポートされています:ゼロであっても、いくつであっても。
イージーモック
| |
atLeastOnce
メソッドが
atLeastOnce
ことを考えると、これは少し奇妙です。 少なくとも3つの呼び出しを期待するには、次のコードのようなものを書く必要があります。
| |
スタブ
メソッドがいつどのように呼び出されるかは原則としてあまり重要ではないことがよくありますが、メソッドが存在して何かを返すのは興味深いことです。
ジョモック
| |
allowing
代わりに
allowing
ignoring
すると言うことができます。 また、必要に応じて、1つの大きなスタブでMockオブジェクト全体を簡単に作成できます。
| |
イージーモック
| |
| |
0
、
false
または
null
)を返します。
String
を含む
null
が返され
null
が 、このクラスのJMockでは、デフォルト値は空の文字列です。
メソッド呼び出し順序の確認
多くの場合、メソッドが呼び出される順序は重要であることが判明しています。 妄想に陥ったと仮定し、ファイルをダウンロードした直後に、ダウンロードして参照ファイルと比較することにしました。 アプリケーションが実際にこれを行うことを確認するには(そうでない場合、あまり信頼しません...) 、これを行うことができます:
ジョモック
| |
inSequence
は、モックオブジェクトへの呼び出しの順序のみを監視し、その直後にそれが示されることを覚えて
inSequence
ことが重要です。 したがって、10個の異なる呼び出しが厳密な順序で行われることを追跡するには、
inSequence
10回記述する必要があります。 しかし、 あなたは一度にいくつかのシーケンスで電話を切ることができます 。
イージーモック
| |
control
全体を厳密に
control
ことができ (最初の例を参照)、その後、含まれるすべてのモックの一般的な順序がチェックされます。 さらに、
createStrictMock
と言うことで、作成時にすぐにモックまたは制御を厳密にすることができます 。 もちろん、そのような量の緑は深刻なマイナスで希釈する必要があります。1つのモック(またはコントロール) が複数のシーケンスに参加することはできません 。 そのようなことすらありません。
メソッド呼び出しが許可される条件
場合によっては、アプリケーションの状態をシミュレートする必要があります。これは、いくつかのメソッドが呼び出されると変化し、他のメソッド(または同じメソッド)が呼び出されるとチェックされます。 アプリケーションを2つの楕円インスタンス(インスタンスはpanolaおよびyarboと呼ばれます)のいずれかに移動してファイルをダウンロードし、ダウンロードした同じインスタンスからダウンロードする必要があります。 これも確認できます。
ジョモック
| |
when
を確認し、thenを使用して新しいアプリケーションを設定します。 とても快適 。 オートマトンプログラミングパラダイムの支持者は、おそらく自分の夢をテストする方法を見つけたと考えています。
EasyMock: アナログなし
マルチスレッドコードテスト
一般的に、マルチスレッドコードのテストは非常に困難です。特定のスレッドが1つまたは別のアクションを実行するタイミングにはさまざまな組み合わせがあるためです。 特に、すべてをクリティカルセクションとして宣言せず、最小限のロックで対処しようとする場合。 私たちは今、すばらしいアプリケーションから抽象化し、さまざまなライブラリーでのマルチスレッドのサポートがどのように行われているかを直接見ていきます。
ジョモック
正直なところ、私にとってそれはひどい苦痛でした:この問題に関するドキュメント(とにかく、 他の多くのものについて)はかなり比fig的であり、したがって、私は試行錯誤で行動しなければなりませんでした、それほど単純ではありませんでした) 。 その結果、手動でダウンロードしたバージョンのhamcrest-core 1.3.0RC1と次のコードを使用して、手動でダウンロードしたバージョンのJMock 2.6.0-RC2によって保存されました。
| |
イージーモック
すぐに使用できるマルチスレッド化を完全にサポートしています。 さらに、記録中に
makeThreadSafe(mock, false)
を使用して無効にし、必要に応じて、
checkIsUsedInOneThread(mock, true)
と言って、1つのスレッドからモックが使用されたことを確認し
checkIsUsedInOneThread(mock, true)
模擬クラス
テストでモックに置き換える必要があるモジュールの開発者は、インターフェイスを作成することを気にせず、特定のクラスしか持っていないことが判明する場合があります。 幸いなことに、このクラスがfinalでなく、finalメソッドを持たない場合、モックを作成できます。
ジョモック
| |
setImposteriser
メソッドを呼び出すこと
setImposteriser
です。 例では、これは2行目で発生します。
イージーモック
| |
部分的なモック
それでも時々、クラスメソッドの一部でのみモックを作成し、残りの部分には手を触れないようにする必要がある場合があります。
JMock: そのような機会はありません
イージーモック
| |
おわりに
これで例と比較が完了しました。 これまで読んだすべての人が、両方のライブラリの使用方法を知っており、将来、習得したスキルを使用して、多くの間違いから自分自身を救うことを願っています。おそらく読者は、「プロジェクトで何を使うべきですか?」という質問に対する私からの回答を待っているのでしょう。 JMockまたはEasyMock?」 ここでの答えは非常にシンプルで明確です。「プロジェクトの要件に依存します。 これらの各ライブラリはツールであり、各ライブラリを使用できる必要があり、特定のタスクに使用するライブラリを選択する必要があります。
それだけです 興味深い質問やコメントを待っています!