web-dev-qa-db-ja.com

異なるパラメーターを持つ複数のメソッド呼び出しを検証する方法

動作を確認したい次のメソッドがあります

public void methodToTest( Exception e, ActionErrors errors ) {

    ...
        errors.add( "exception.message", 
                    ActionMessageFactory.createErrorMessage(e.toString() ));

        errors.add( "exception.detail",
                    ActionMessageFactory.createErrorMessage(e.getStackTrace()[0].toString() ));

    ...
}

@Testクラスでは、errors.add()が "exception.message"で呼び出され、再び "exception.detail"で呼び出されることを確認するために、このようなことを望んでいました。

verify(errors).add(eq("exception.message"), any(ActionError.class));
verify(errors).add(eq("exception.detail"), any(ActionError.class));

しかし、Mockitoは次のように文句を言います

Argument(s) are different! Wanted:
actionErrors.add(
    "exception.message",
    <any>
);

Actual invocation has different arguments:
actionErrors.add(
    "exception.detail",
    org.Apache.struts.action.ActionError@38063806
);

Mockitoに両方の値をチェックするように指示するにはどうすればよいですか?

96
Brad

さらに読むと、ArgumentCaptorsと次の作品を使用するようになりましたが、私は望んでいるよりもはるかに冗長です。

ArgumentCaptor<String> argument = ArgumentCaptor.forClass(String.class);

verify(errors, atLeastOnce()).add(argument.capture(), any(ActionMessage.class));

List<String> values = argument.getAllValues();

assertTrue(values.contains("exception.message"));
assertTrue(values.contains("exception.detail"));
95
Brad

両方のadd()呼び出しの順序が関連する場合、InOrderを使用できます。

InOrder inOrder = inOrder(errors, errors);
inOrder.verify(errors).add(eq("exception.message"), any(ActionError.class));
inOrder.verify(errors).add(eq("exception.detail"), any(ActionError.class));
50

次のようなものを試してください:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));
23
John B

コードに問題がある可能性があります。実際、あなたは実際にこのコードを書くからです:

Map<Character, String> map = mock(Map.class);

map.put('a', "a");
map.put('b', "b");
map.put('c', "c");

verify(map).put(eq('c'), anyString());
verify(map).put(eq('a'), anyString());
verify(map).put(eq('b'), anyString());

最初の検証は、実際の呼び出しに関して順序が揃っていないことに注意してください。

また、ストラット型など、所有していない型を実際にモックしないことをお勧めします。

[EDIT @Brad]

IDEでBriceのコード(上記)を実行した後、ActionMessageの代わりにActionErrorを使用したことがわかります。そのため、verify()が一致しませんでした。最初に投稿したエラーメッセージは、それが一致しなかった最初の引数だと誤解させていました。それは2番目の引数だったことがわかります。

だから私の質問への答えは

/** 
 * note that ActionMessageFactory.createErrorMessage() returns ActionMessage
 * and ActionError extends ActionMessage
 */
verify(errors).add(eq("exception.message"), any(ActionMessage.class));
verify(errors).add(eq("exception.detail"), any(ActionMessage.class));
16
Brice

Mockito.atLeastOnce()を使用すると、そのmockObjectが何度も呼び出される場合でも、Mockitoがテストに合格できます。

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));
8
sendon1982

@ sendon1928と同様の方法で、以下を使用できます。

Mockito.times(wantedInvocationCount)

メソッドが正確な回数呼び出されたことを確認するために(私の意見では好ましい解決策)。その後、電話することができます

Mockito.verifyNoMoreInteractions(mock)

モックがどのコンテキストでもこれ以上使用されないようにするため。完全な例:

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(1));

Mockito.verify(mockObject, Mockito.times(wantedInvocationCount)).testMethod(Mockito.eq(2));

Mockito.verifyNoMoreInteractions(mockObject)
0