web-dev-qa-db-ja.com

Mockitoでメソッドを無効にするモックを作成する方法

Void型の戻り値を持つメソッドをモックする方法

オブザーバパターンを実装しましたが、Mockitoでモックすることはできません。

そして私はインターネットで例を見つけようとしましたが、成功しませんでした。

私のクラスはこんな感じです:

public class World {

    List<Listener> listeners;

    void addListener(Listener item) {
        listeners.add(item);
    }

    void doAction(Action goal,Object obj) {
        setState("i received");
        goal.doAction(obj);
        setState("i finished");
    }

    private string state;
    //setter getter state
} 

public class WorldTest implements Listener {

    @Test public void Word{
    World  w= mock(World.class);
    w.addListener(this);
    ...
    ...

    }
}

interface Listener {
    void doAction();
}

システムはモックで起動されません。 =(上記のシステム状態を表示したい。それらに従ってアサーションを行う。

806
ibrahimyilmaz

いわゆる問題の解決策は、spyMockito.mock(..) の代わりにmockMockito.spy(...) を使用することです。

スパイは私たちが部分的にモックすることを可能にします。 Mockitoはこの件が得意です。まだ完成していないクラスがあるので、このようにしてこのクラス内の必要な場所をモックします。

52
ibrahimyilmaz

Mockito APIドキュメント を見てください。リンクされたドキュメントが言及しているように(Point#12)、Mockitoフレームワークからvoidメソッドを模擬するために、doThrow()doAnswer()doNothing()doReturn()のいずれかのメソッドファミリーを使用することができます。

例えば、

Mockito.doThrow(new Exception()).when(instance).methodName();

あるいはフォローアップ行動と組み合わせたい場合は、

Mockito.doThrow(new Exception()).doNothing().when(instance).methodName();

以下のクラスWorldでセッターsetState(String s)をモックするのを見ていると仮定すると、コードはdoAnswerメソッドを使ってsetStateをモックします。

World  mockWorld = mock(World.class); 
doAnswer(new Answer<Void>() {
    public Void answer(InvocationOnMock invocation) {
      Object[] args = invocation.getArguments();
      System.out.println("called with arguments: " + Arrays.toString(args));
      return null;
    }
}).when(mockWorld).setState(anyString());
1018
sateesh

私はその質問に対するもっと簡単な答えを見つけたと思います、本当のメソッドをただ一つのメソッドのために呼び出すために(それが無効な戻り値を持っているとしても)あなたはこれをすることができます:

Mockito.doCallRealMethod().when(<objectInstance>).<method>();
<objectInstance>.<method>();

あるいは、そのクラスのすべてのメソッドに対して実際のメソッドを呼び出すこともできます。

<Object> <objectInstance> = mock(<Object>.class, Mockito.CALLS_REAL_METHODS);
93
MarcioB

@sateeshが言ったことに加えて、テストがそれを呼び出さないようにするために単にvoidメソッドをモックしたいときは、このようにSpyを使うことができます。

World world = new World();
World spy = Mockito.spy(world);
Mockito.doNothing().when(spy).methodToMock();

テストを実行するときは、spyオブジェクトではなくworldオブジェクトに対してtestのメソッドを必ず呼び出してください。例えば:

assertEquals(0,spy.methodToTestThatShouldReturnZero());
61
Omri374

まず第一に:あなたは常にmockito staticをインポートするべきです。こうすればコードはずっと読みやすく(そして直感的に)なります:

import static org.mockito.Mockito.*;

部分的なモックを作成し、それでも元の機能を残りのモックに維持するために、 "Spy"を提供しています。

あなたは次のようにそれを使用することができます:

private World world = spy(World.class);

メソッドが実行されないようにするには、次のようにします。

doNothing().when(someObject).someMethod(anyObject());

メソッドにカスタム動作を与えるには、 "thenReturn"と共に "when"を使用します。

doReturn("something").when(this.world).someMethod(anyObject());

他の例については、ドキュメントの中のmockitoサンプルを見つけてください。

23
fl0w

mockitoでvoidメソッドをモックする方法 - 2つの選択肢があります。

  1. doAnswer - モックされたvoidメソッドに何かをさせたい場合(voidにもかかわらず振る舞いをモックする).
  2. doThrow - モックのvoidメソッドから例外をスローしたい場合はMockito.doThrow()があります。

以下はその使い方の例です(理想的なユースケースではありませんが、基本的な使い方を説明したいだけです)。

@Test
public void testUpdate() {

    doAnswer(new Answer<Void>() {

        @Override
        public Void answer(InvocationOnMock invocation) throws Throwable {
            Object[] arguments = invocation.getArguments();
            if (arguments != null && arguments.length > 1 && arguments[0] != null && arguments[1] != null) {

                Customer customer = (Customer) arguments[0];
                String email = (String) arguments[1];
                customer.setEmail(email);

            }
            return null;
        }
    }).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("[email protected]", "[email protected]");

    //some asserts
    assertThat(customer, is(notNullValue()));
    assertThat(customer.getEmail(), is(equalTo("[email protected]")));

}

@Test(expected = RuntimeException.class)
public void testUpdate_throwsException() {

    doThrow(RuntimeException.class).when(daoMock).updateEmail(any(Customer.class), any(String.class));

    // calling the method under test
    Customer customer = service.changeEmail("[email protected]", "[email protected]");

}
}

Mockitoを使った mock および test void メソッドの使い方の詳細については、 Mockitoを使ってモックする方法(例を含む総合ガイド)

19

束に別の回答を追加する.

スパイを使用したくない場合はdoAnswerメソッドを呼び出す必要があります。しかし、あなたは必ずしもあなた自身の 回答 をロールする必要はありません。いくつかのデフォルトの実装があります。特に、 CallsRealMethods

実際には、これは次のようになります。

doAnswer(new CallsRealMethods()).when(mock)
        .voidMethod(any(SomeParamClass.class));

または

doAnswer(Answers.CALLS_REAL_METHODS.get()).when(mock)
        .voidMethod(any(SomeParamClass.class));
14
javamonkey79

Java 8では、org.mockito.Mockito.doAnswerの静的インポートがあると仮定すると、これは少しきれいになります。

doAnswer(i -> {
  // Do stuff with i.getArguments() here
  return null;
}).when(*mock*).*method*(*methodArguments*);

return null;は重要で、それがなければコンパイルはdoAnswerの適切なオーバーライドを見つけることができないので、かなりあいまいなエラーで失敗します。

たとえば、execute()に渡されたExecutorServiceをただちに実行するRunnableは、次のように実装できます。

doAnswer(i -> {
  ((Runnable) i.getArguments()[0]).run();
  return null;
}).when(executor).execute(any());
8
Tim B

あなたの問題はあなたのテスト構造によるものだと思います。私がモックをテストクラスにインターフェースを実装する伝統的な方法と混ぜるのは難しいことがわかりました(ここでやったように)。

リスナーをモックとして実装した場合は、対話を検証できます。

Listener listener = mock(Listener.class);
w.addListener(listener);
world.doAction(..);
verify(listener).doAction();

これは、「世界」が正しいことをしているというあなたを満足させるはずです。

5
ashley

@ashley:私のために働く

public class AssetChangeListenerImpl extends
AbstractAssetChangeListener implements AssetChangeListener {

  @Override
  public void onChangeEvent(final EventMessage message) throws EventHubClientException {
      execute(message);
    }
  }
}

public class AbstractAssetChangeListener {
  protected  void execute( final EventMessage message ) throws EventHubClientException {
    executor.execute( new PublishTask(getClient(), message) );
} } @RunWith(MockitoJUnitRunner.class) public class AssetChangeListenerTest extends AbstractAssetChangeListenerTest {

 public void testExecute() throws EventHubClientException {
    EventMessage message = createEventMesage(EventType.CREATE);
    assetChangeListener.execute(message);
    verify(assetChangeListener, times(1)).execute(message);
} }
0
Yoga Gowda