mockito 如何验证具有不同参数的多个方法调用

ffvjumwh  于 2022-11-08  发布在  其他
关注(0)|答案(7)|浏览(271)

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

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检查这两个值?

ars1skjm

ars1skjm1#

进一步的阅读使我尝试使用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"));
68de4m5k

68de4m5k2#

如果两个add()调用的顺序相关,则可以使用InOrder

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

h4cxqtbf3#

请尝试以下操作:

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

q3qa4bjr4#

您可以使用Mockito.atLeastOnce(),它允许Mockito通过测试,即使该mockObject将被调用多次。

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

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

bvn4nwqk5#

你可能在你的代码中有问题。因为事实上你实际上写了这样的代码:

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

请注意,第一次验证在实际调用方面甚至没有按顺序进行。
另外,我建议你不要嘲笑你不拥有的类型,比如struts类型。

[编辑@布拉德]

在我的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));
hof1towb

hof1towb6#

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

OP代码正确;它会检查您需要什么。
您的问题出在您的产品代码中,它(似乎)从未调用过具有ActionError参数类型的第一个参数组合。因此Mokito正确地提出了投诉。但是(我同意)投诉消息对于多次调用是混乱的。
解决方案:确保(首先)您确实精确地调用了该方法2次(使用任何参数)。

ndasle7k

ndasle7k7#

与@sendon1928类似,我们可以使用:

Mockito.times(wantedInvocationCount)

以确保方法被调用了确切的次数(我认为是更好的解决方案)。

Mockito.verifyNoMoreInteractions(mock)

确保mock不会在任何上下文中进一步使用。完整示例:

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

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

Mockito.verifyNoMoreInteractions(mockObject)

相关问题