web-dev-qa-db-ja.com

EasyMockで複数のインターフェースを実装するモックオブジェクトを作成することは可能ですか?

EasyMockでいくつかのインターフェースを実装するモックオブジェクトを作成することは可能ですか?

たとえば、インターフェースFooおよびインターフェースCloseable

Rhino Mocksでは、モックオブジェクトを作成するときに複数のインターフェースを提供できますが、EasyMockのcreateMock()メソッドは1つのタイプしか使用できません。

EasyMockでこれを実現することは可能ですか?FooCloseableの両方を拡張する一時的なインターフェースを作成し、それをモックするフォールバックに頼る必要はありませんか?

42
Daniel Fortunov

EasyMockはこれをサポートしていないため、一時的なインターフェースのフォールバックに悩まされています。

余談ですが、コードの少しのにおいがします-メソッドは実際にオブジェクトを2つの異なるものとして処理する必要があります。この場合、FooおよびCloseableインターフェースですか?

これは、メソッドが複数の操作を実行していることを意味し、それらの操作の1つはCloseableを「閉じる」ことであると思われますが、呼び出し元のコードが「 「閉じる」が必要ですか?

この方法でコードを構造化すると、「オープン」と「クローズ」が同じtry ... finallyブロックとIMHOは、コードをより一般的な方法は言うまでもなく読みやすくし、Fooのみを実装するオブジェクトを渡すことができます。

10
Nick Holt

私は基本的にニック・ホルトの答えに同意しますが、 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) {
        }
    }
73
Thomas Dufour

あなたは次のようなものを考えましたか:

interface Bar extends Foo, Closeable {
}

そして、モックインターフェースバー?

14
extraneon

最も投票された回答 の代替案は、まだMockitoに基づいていますが、注釈が付いています。次のように、extraInterfacesアノテーションから Mock を直接設定できます。

_@RunWith(MockitoJUnitRunner.class)
public class MyTest {
    @Mock(extraInterfaces = Closeable.class)
    private Foo foo;
    ...
}
_

NB:extraInterfacesは_Class<?>[]_型なので、必要に応じて複数のインターフェイスを指定できます。

追加のインターフェースのメソッド呼び出しをモックする必要がある場合は、モックをキャストする必要があります。たとえば、モックIOExceptionclose()を呼び出すときにfooをスローしたい場合、対応するコードは次のようになります。

_Mockito.doThrow(IOException.class).when((Closeable) foo).close();
_
5
Nicolas Filotto

この問題を解決する別の方法は、 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();

これが良いアイデアであるかどうかにかかわらず、それは議論次第です...

2
Haroldo_OK

私の知る限りでは、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();
}

DependencyRunnableはインターフェースです。 doSomethingメソッドは最初のメソッドに属し、runは2番目のメソッドに属します。

2
Rogério