Mockito:doAnswer対thenReturn


124

後のユニットテストのためにMockitoを使用しています。doAnswervsをいつ使用するか混乱していますthenReturn

誰かが詳細に私を助けてくれますか?これまでのところ、で試しましたthenReturn

回答:


167

メソッド呼び出しをモックするときの戻り値がわかっている場合に使用するthenReturn必要doReturnがあります。この定義された値は、モックメソッドを呼び出すと返されます。

thenReturn(T value) メソッドが呼び出されたときに返される戻り値を設定します。

@Test
public void test_return() throws Exception {
    Dummy dummy = mock(Dummy.class);
    int returnValue = 5;

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenReturn(returnValue);
    doReturn(returnValue).when(dummy).stringLength("dummy");
}

Answer モックされたメソッドが呼び出されたときに追加のアクションを実行する必要がある場合、たとえば、このメソッド呼び出しのパラメーターに基づいて戻り値を計算する必要がある場合に使用されます。

doAnswer()ジェネリックでvoidメソッドをスタブしたい場合に使用しますAnswer

Answerは、実行されるアクションと、モックを操作したときに返される戻り値を指定します。

@Test
public void test_answer() throws Exception {
    Dummy dummy = mock(Dummy.class);
    Answer<Integer> answer = new Answer<Integer>() {
        public Integer answer(InvocationOnMock invocation) throws Throwable {
            String string = invocation.getArgumentAt(0, String.class);
            return string.length() * 2;
        }
    };

    // choose your preferred way
    when(dummy.stringLength("dummy")).thenAnswer(answer);
    doAnswer(answer).when(dummy).stringLength("dummy");
}

こんにちは@Roland Weislederですが、値を生成した内部コードを返し、引数とは何の関係もない場合があります。たとえばcode = UUID.randomUUID()、これをで実装することは不可能mockitoです。
zhuguowei 2016

3
モックが呼び出しごとに新しいUUIDを返す必要がある場合は、Answerjust with を実装しreturn UUID.randomUUID();ます。
Roland Weisleder 2016

このメソッドを新しいAnswer初期化から取得して、コードをもう少しきれいにするために、いくつかのメソッドに配置できますか?
ライン

3
@Line Answerは関数型インターフェースであるため、Java 8ではラムダ式に置き換えることができます。が十分にクリーンでない場合、他の通常の異常なリファクタリングが可能です。
Roland Weisleder、2017年

@ zhuguowei:いくつかの値が生成された内部コードを返しますか?それはどういう意味ですか?
Saurabh Patil

34

doAnswer次のthenReturn場合も同じことを行います。

  1. あなたはスパイではなくモックを使っています
  2. スタブしているメソッドは、voidメソッドではなく値を返します。

このBookServiceをモックしましょう

public interface BookService {
    String getAuthor();
    void queryBookTitle(BookServiceCallback callback);
}

doAnswerおよびを使用してgetAuthor()をスタブできthenReturnます。

BookService service = mock(BookService.class);
when(service.getAuthor()).thenReturn("Joshua");
// or..
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        return "Joshua";
    }
}).when(service).getAuthor();

を使用する場合doAnswer、メソッドをに渡すことはできませんwhen

// Will throw UnfinishedStubbingException
doAnswer(invocation -> "Joshua").when(service.getAuthor());

では、doAnswer代わりにthenReturnいつ使用しますか?私は2つのユースケースを考えることができます:

  1. voidメソッドを「スタブ」したい場合。

doAnswerを使用すると、メソッドの呼び出し時にいくつかの追加アクションを実行できます。たとえば、queryBookTitleでコールバックをトリガーします。

BookServiceCallback callback = new BookServiceCallback() {
    @Override
    public void onSuccess(String bookTitle) {
        assertEquals("Effective Java", bookTitle);
    }
};
doAnswer(new Answer() {
    @Override
    public Object answer(InvocationOnMock invocation) throws Throwable {
        BookServiceCallback callback = (BookServiceCallback) invocation.getArguments()[0];
        callback.onSuccess("Effective Java");
        // return null because queryBookTitle is void
        return null;
    }
}).when(service).queryBookTitle(callback);
service.queryBookTitle(callback);
  1. モックの代わりにスパイを使用している場合

Spy Mockitoでwhen-thenReturnを使用すると、実際のメソッドが呼び出され、回答がスタブされます。このサンプルのように、実際のメソッドを呼び出さない場合は、問題が発生する可能性があります。

List list = new LinkedList();
List spy = spy(list);
// Will throw java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
when(spy.get(0)).thenReturn("java");
assertEquals("java", spy.get(0));

doAnswerを使用すると、安全にスタブを作成できます。

List list = new LinkedList();
List spy = spy(list);
doAnswer(invocation -> "java").when(spy).get(0);
assertEquals("java", spy.get(0));

実際、メソッドの呼び出し時に追加のアクションを実行したくない場合は、を使用できますdoReturn

List list = new LinkedList();
List spy = spy(list);
doReturn("java").when(spy).get(0);
assertEquals("java", spy.get(0));

モックされたメソッドが無効な場合はどうなりますか?
Igor Donin

1
Igor、まさにdoAnswer()が登場するところです。彼は上記の答えでそれをカバーしました。
Saurabh Patil、

使用するとdoAnswer(new Answer() { ... return null;}、「答えは生の型です。総称型Answer <T>への参照はパラメーター化する必要があります」という警告がEclipseで表示されます。これを解決する方法はありますか(警告ofcを無視することを除く)?
LazR
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.