EasyMockでいくつかのインターフェースを実装するモックオブジェクトを作成することは可能ですか?
たとえば、インターフェースFoo
およびインターフェースCloseable
?
Rhino Mocksでは、モックオブジェクトを作成するときに複数のインターフェースを提供できますが、EasyMockのcreateMock()
メソッドは1つのタイプしか使用できません。
EasyMockでこれを実現することは可能ですか?Foo
とCloseable
の両方を拡張する一時的なインターフェースを作成し、それをモックするフォールバックに頼る必要はありませんか?
EasyMockはこれをサポートしていないため、一時的なインターフェースのフォールバックに悩まされています。
余談ですが、コードの少しのにおいがします-メソッドは実際にオブジェクトを2つの異なるものとして処理する必要があります。この場合、Foo
およびCloseable
インターフェースですか?
これは、メソッドが複数の操作を実行していることを意味し、それらの操作の1つはCloseable
を「閉じる」ことであると思われますが、呼び出し元のコードが「 「閉じる」が必要ですか?
この方法でコードを構造化すると、「オープン」と「クローズ」が同じtry ... finally
ブロックとIMHOは、コードをより一般的な方法は言うまでもなく読みやすくし、Foo
のみを実装するオブジェクトを渡すことができます。
私は基本的にニック・ホルトの答えに同意しますが、 mockito は次の呼び出しであなたが要求することを行うことができることを指摘しなければならないと思いました:
Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class));
明らかに、キャストを使用する必要があります:(Bar)mock
モックをBar
として使用する必要があるが、そのキャストではClassCastException
がスローされない場合
これは、まったくばかげているとはいえ、もう少し完全な例です。
import static org.junit.Assert.fail;
import org.junit.Test;
import static org.mockito.Mockito.*;
import org.mockito.Mockito;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
import org.hamcrest.Matchers;
import Java.util.Iterator;
public class NonsensicalTest {
@Test
public void testRunnableIterator() {
// This test passes.
final Runnable runnable =
mock(Runnable.class, withSettings().extraInterfaces(Iterator.class));
final Iterator iterator = (Iterator) runnable;
when(iterator.next()).thenReturn("a", 2);
doThrow(new IllegalStateException()).when(runnable).run();
assertThat(iterator.next(), is(Matchers.<Object>equalTo("a")));
try {
runnable.run();
fail();
}
catch (IllegalStateException e) {
}
}
あなたは次のようなものを考えましたか:
interface Bar extends Foo, Closeable {
}
そして、モックインターフェースバー?
最も投票された回答 の代替案は、まだMockitoに基づいていますが、注釈が付いています。次のように、extraInterfaces
アノテーションから Mock
を直接設定できます。
_@RunWith(MockitoJUnitRunner.class)
public class MyTest {
@Mock(extraInterfaces = Closeable.class)
private Foo foo;
...
}
_
NB:extraInterfaces
は_Class<?>[]
_型なので、必要に応じて複数のインターフェイスを指定できます。
追加のインターフェースのメソッド呼び出しをモックする必要がある場合は、モックをキャストする必要があります。たとえば、モックIOException
でclose()
を呼び出すときにfoo
をスローしたい場合、対応するコードは次のようになります。
_Mockito.doThrow(IOException.class).when((Closeable) foo).close();
_
この問題を解決する別の方法は、 CGLibミックスイン を使用することです。
final Interface1 interface1 = mockery.mock(Interface1.class);
final Interface2 interface2 = mockery.mock(Interface2.class);
service.setDependence(Mixin.create(new Object[]{ interface1, interface2 }));
mockery.checking(new Expectations(){{
oneOf(interface1).doSomething();
oneOf(interface2).doNothing();
}});
service.execute();
これが良いアイデアであるかどうかにかかわらず、それは議論次第です...
私の知る限りでは、Javaの複数のインターフェースのモックを明示的にサポートしているモックツールは JMockit のみです(この機能を追加するための私のインスピレーションはMoqからのものです)と.NETツールであるRhino Mocks)
例(mockit.ExpectationsUsingMockedTest
JUnit 4テストクラスから):
@Test
public <M extends Dependency & Runnable> void mockParameterWithTwoInterfaces(final M mock)
{
new Expectations()
{
{
mock.doSomething(true); returns("");
mock.run();
}
};
assertEquals("", mock.doSomething(true));
mock.run();
}
Dependency
とRunnable
はインターフェースです。 doSomething
メソッドは最初のメソッドに属し、run
は2番目のメソッドに属します。