如何使用不同的参数验证多个方法调用

Bra*_*rad 99 java mockito

我有以下方法,我希望验证行为

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() ));

    ...
}
Run Code Online (Sandbox Code Playgroud)

在我的@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));
Run Code Online (Sandbox Code Playgroud)

但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
);
Run Code Online (Sandbox Code Playgroud)

我怎么能告诉Mockito检查这两个值?

Bra*_*rad 96

进一步阅读使我尝试使用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"));
Run Code Online (Sandbox Code Playgroud)


Chr*_*sch 55

如果两个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));
Run Code Online (Sandbox Code Playgroud)

  • 传递单个`errors`参数就足够了:`InOrder inOrder = inOrder(errors);`(参见[docs](http://javadoc.io/page/org.mockito/mockito-core/latest/org/mockito /Mockito.html#in_order_verification)) (6认同)
  • 如果订单不相关怎么办?这是常见的情况。 (2认同)

Joh*_*n B 23

尝试这样的事情:

verify(errors, times(2))
     .add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
          any(ActionError.class));
Run Code Online (Sandbox Code Playgroud)

  • 你的支票显然太放松了。 (8认同)

Bri*_*ice 16

你的代码可能有问题.因为事实上你实际上写了这段代码:

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());
Run Code Online (Sandbox Code Playgroud)

请注意,就实际调用而言,第一次验证甚至不是有序的.

另外,我建议你实际上不要模拟你不拥有的类型,例如struts类型.

[编辑@Brad]

在我的IDE中运行Brice的代码(上面)后,我可以看到我使用了ActionError而不是ActionMessage,所以这就是我的verify()不匹配的原因.我最初发布的错误消息误导我认为这是第一个不匹配的参数.事实证明这是第二个论点.

所以我的问题的答案是

/** 
 * 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));
Run Code Online (Sandbox Code Playgroud)


epo*_*pox 11

OP 代码正确(检查您的总计)

=1= 告诉 Mokito 总的呼叫期望。

=2= 告诉 Mokito 每个参数组合预期出现多少次。(如果times被省略,Mokito 假设times(1))。

verify(errors, times(2)).add(any(), any(ActionMessage.class));

verify(errors).add(eq("exception.message"), any());
verify(errors).add(eq("exception.detail"), any());
Run Code Online (Sandbox Code Playgroud)

OP码正确;它会检查你需要什么。

您的问题出在您的 Prod 代码中,该代码(似乎)从未使用ActionError arg 类型调用第一个 arg 组合。所以 Mokito 的抱怨是正确的。然而(我同意)投诉信息对于多次通话来说是令人困惑的。

解决方案:确保(首先)您确实精确地调用了该方法两次(使用任何参数)。


sen*_*982 10

您可以使用Mockito.atLeastOnce()哪个允许Mockito传递测试,即使该mockObject将被多次调用.

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

Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));
Run Code Online (Sandbox Code Playgroud)