これについての考え方の1つは、コードの設計に関心がある場合は、EasyMockが期待の概念によってフィードバックを提供するため、より適切な選択です。
テストの保守性(読み取り、書き込みが簡単で、変更による影響が少ない脆弱性の少ないテスト)を重視する場合は、Mockitoの方が適しているようです。
私の質問は次のとおりです。
- 大規模なプロジェクトでEasyMockを使用したことがある場合、テストの保守が難しいと思いますか?
- Mockitoの制限は何ですか(エンドテスト以外)?
これらのフレームワークのテストの可読性、サイズ、またはテスト手法については議論しません。これらは同等であると思いますが、簡単な例で違いを示します。
与えられた:どこかに何かを保存する責任があるクラスがあります:
public class Service {
public static final String PATH = "path";
public static final String NAME = "name";
public static final String CONTENT = "content";
private FileDao dao;
public void doSomething() {
dao.store(PATH, NAME, IOUtils.toInputStream(CONTENT));
}
public void setDao(FileDao dao) {
this.dao = dao;
}
}
そしてそれをテストしたい:
モッキト:
public class ServiceMockitoTest {
private Service service;
@Mock
private FileDao dao;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
// when
service.doSomething();
// then
ArgumentCaptor<InputStream> captor = ArgumentCaptor.forClass(InputStream.class);
Mockito.verify(dao, times(1)).store(eq(Service.PATH), eq(Service.NAME), captor.capture());
assertThat(Service.CONTENT, is(IOUtils.toString(captor.getValue())));
}
}
EasyMock:
public class ServiceEasyMockTest {
private Service service;
private FileDao dao;
@Before
public void setUp() {
dao = EasyMock.createNiceMock(FileDao.class);
service = new Service();
service.setDao(dao);
}
@Test
public void testDoSomething() throws Exception {
// given
Capture<InputStream> captured = new Capture<InputStream>();
dao.store(eq(Service.PATH), eq(Service.NAME), capture(captured));
replay(dao);
// when
service.doSomething();
// then
assertThat(Service.CONTENT, is(IOUtils.toString(captured.getValue())));
verify(dao);
}
}
ご覧のとおり、両方のテストはほぼ同じで、両方とも合格しています。ここで、他の誰かがサービスの実装を変更してテストを実行しようとしていると想像してみましょう。
新しいサービスの実装:
dao.store(PATH + separator, NAME, IOUtils.toInputStream(CONTENT));
PATH定数の最後にセパレータが追加されました
テスト結果は今どのようになりますか?まず、両方のテストが失敗しますが、エラーメッセージが異なります。
EasyMock:
java.lang.AssertionError: Nothing captured yet
at org.easymock.Capture.getValue(Capture.java:78)
at ServiceEasyMockTest.testDoSomething(ServiceEasyMockTest.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
モッキト:
Argument(s) are different! Wanted:
dao.store(
"path",
"name",
<Capturing argument>
);
-> at ServiceMockitoTest.testDoSomething(ServiceMockitoTest.java:34)
Actual invocation has different arguments:
dao.store(
"path\",
"name",
java.io.ByteArrayInputStream@1c99159
);
-> at Service.doSomething(Service.java:13)
EasyMockテストで何が起こったのですか、なぜ結果がキャプチャされなかったのですか?storeメソッドは実行されませんでしたが、ちょっと待ってください。EasyMockが私たちに嘘をついているのはなぜですか。
これは、EasyMockがスタブと検証という2つの責任を1行に混合しているためです。そのため、何かがおかしいと、どの部分が故障の原因であるかを理解するのが困難になります。
もちろん、あなたは私に言うことができます-アサーションの前にテストを変更して検証を移動するだけです。うわー、あなたは真剣ですか、開発者はフレームワークをモックすることによって強制されるいくつかの魔法の秩序を覚えておく必要がありますか?
ちなみに、それは役に立ちません:
java.lang.AssertionError:
Expectation failure on verify:
store("path", "name", capture(Nothing captured yet)): expected: 1, actual: 0
at org.easymock.internal.MocksControl.verify(MocksControl.java:111)
at org.easymock.classextension.EasyMock.verify(EasyMock.java:211)
それでも、メソッドは実行されなかったと私に言っていますが、実行されたのは別のパラメーターのみでした。
なぜMockitoが優れているのですか?このフレームワークは、2つの責任を1つの場所に混在させることはなく、テストが失敗した場合、その理由を簡単に理解できます。
コードの設計に関心がある場合は、Easymockが期待の概念によってフィードバックを提供するため、より適切な選択です。
面白い。「期待の概念」により、多くの開発者はUnexpectedMethodCallの問題を満たすためだけに、テストにますます多くの期待を置くようになることがわかりました。それはデザインにどのように影響しますか?
コードを変更しても、テストは中断されません。機能が動作を停止すると、テストが中断するはずです。コードが変更されたときにテストが中断するのが好きな場合は、Javaファイルのmd5チェックサムをアサートするテストを作成することをお勧めします:)
私はEasyMock開発者なので少し部分的ですが、もちろん大規模なプロジェクトでEasyMockを使用しました。
私の意見では、EasyMockテストは確かにたまに失敗するでしょう。EasyMockは、期待することを完全に記録することを強制します。これにはある程度の規律が必要です。テストされたメソッドが現在必要としているものではなく、期待されているものを実際に記録する必要があります。たとえば、モックでメソッドが何度呼び出されてもかまわない場合は、を使用することを恐れないでくださいandStubReturn
。また、パラメータを気にしない場合は、などを使用anyObject()
してください。TDDで考えることはそれを助けることができます。
私の分析によると、EasyMockテストはより頻繁に失敗しますが、Mockitoテストは必要なときに失敗します。私は自分のテストを破ることを好みます。少なくとも、自分の開発の影響は何かを知っています。もちろん、これは私の個人的な見解です。
私はあなたがこれについてあまり心配するべきではないと思います。EasymockとMockitoはどちらも、「strict」または「nice」に構成できます。唯一の違いは、デフォルトではEasymockがstrictであり、Mockitoが優れていることです。
すべてのテストと同様に、厳格なルールはありません。テストの信頼性と保守性のバランスをとる必要があります。私は通常、「厳密な」モックを使用するために高いレベルの信頼性を要求する特定の機能または技術分野があることに気付きます。たとえば、debitAccount()メソッドが複数回呼び出されることはおそらく望ましくありません。ただし、モックが実際にはスタブにすぎないため、コードの実際の「肉」をテストできる場合もあります。
Mockitoの初期の頃はAPIの互換性が問題でしたが、現在ではより多くのツールがフレームワークをサポートしています。Powermock(個人的なお気に入り)にmockito拡張機能が追加されました
正直に言うとモッキートが好きです。EasyMockをunitilsで使用していて、両方を組み合わせると、多くの場合、IllegalArgumentException:インターフェイスではなくMissingBehaviorExceptionsなどの例外が発生します。どちらの場合も、コードとテストコードは完全に問題ありません。MissingBehaviorExceptionは、createMock(classextentions !!を使用)で作成されたモックオブジェクトがこのエラーを生成したことが原因であるように見えました。@Mockを使用すると、機能しました。私はそのような誤解を招くような振る舞いが好きではありません。それは私にとって、その開発者が彼らが何をしているのかわからないことを明確に示しています。優れたフレームワークは、常に使いやすく、曖昧であってはなりません。IllegalArgumentExceptionは、EasyMock内部のいくつかの混合によるものでもありました。また、録音は私がやりたいことではありません。コードが例外をスローするかどうか、そして期待される結果を返すかどうかをテストしたいと思います。それをコードカバレッジと組み合わせると、私にとって適切なツールになります。パフォーマンスが向上するなどの理由で、前のコードの上または下に1行のコードを配置するたびに、テストが中断することは望ましくありません。mockitoでは問題ありません。EasyMockを使用すると、コードが壊れていなくてもテストが失敗します。それは悪いです。時間、つまりお金がかかります。期待される動作をテストする必要があります。あなたは本当に物事の順序を気にしますか?まれにあなたがそうするかもしれないと思います。その後、Easymockを使用します。それ以外の場合は、mockitoを使用してテストを作成するために費やす時間が大幅に短縮されると思います。パフォーマンスが向上するなどの理由で、前のコードの上または下に1行のコードを配置するたびに、テストが中断することは望ましくありません。mockitoでは問題ありません。EasyMockを使用すると、コードが壊れていなくてもテストが失敗します。それは悪いです。時間、つまりお金がかかります。期待される動作をテストする必要があります。あなたは本当に物事の順序を気にしますか?まれにあなたがそうするかもしれないと思います。その後、Easymockを使用します。それ以外の場合は、mockitoを使用してテストを作成するために費やす時間が大幅に短縮されると思います。パフォーマンスが向上するなどの理由で、前のコードの上または下に1行のコードを配置するたびに、テストが中断することは望ましくありません。mockitoでは問題ありません。EasyMockを使用すると、コードが壊れていなくてもテストが失敗します。それは悪いです。時間、つまりお金がかかります。期待される動作をテストする必要があります。あなたは本当に物事の順序を気にしますか?まれにあなたがそうするかもしれないと思います。その後、Easymockを使用します。それ以外の場合は、mockitoを使用してテストを作成するために費やす時間が大幅に短縮されると思います。その後、Easymockを使用します。それ以外の場合は、mockitoを使用してテストを作成するために費やす時間が大幅に短縮されると思います。その後、Easymockを使用します。それ以外の場合は、mockitoを使用してテストを作成するために費やす時間が大幅に短縮されると思います。
ローレンスよろしくお願いします