我有以下方法希望验证其行为。
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 检查这两个值?
Mockito.reset()
进一步阅读使我尝试使用 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"));
如果两个 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));
List
转换为 Set
并断言输入集等于参数捕获给定的集。
尝试这样的事情:
verify(errors, times(2))
.add(AdditionalMatchers.or(eq("exception.message"), eq("exception.detail")),
any(ActionError.class));
您可以使用 Mockito.atLeastOnce()
允许 Mockito 通过测试,即使该 mockObject 将被调用多次。
Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(1));
Mockito.verify(mockObject, Mockito.atLeastOnce()).testMethod(Mockito.eq(2));
你的代码可能有问题。因为事实上你实际上是在写这段代码:
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));
InOrder
。
OP 代码正确(检查您的总计)
=1= 告诉 Mokito 总呼叫期望。
=2= 告诉 Mokito 每个参数组合预期的次数。 (Mokito 假设 times(1),如果 times 被省略)。
verify(errors, times(2)).add(any(), any(ActionMessage.class));
verify(errors).add(eq("exception.message"), any());
verify(errors).add(eq("exception.detail"), any());
操作码正确;它检查你需要什么。
您的问题出在您的 Prod 代码中,该代码(似乎)从未使用 ActionError arg 类型调用第一个 arg 组合。所以Mokito正确地抱怨了。但是(我同意)投诉消息对于多个电话来说是令人困惑的。
解决方案:确保(首先)您确实准确地调用了该方法 2 次(使用任何参数)。
与@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)
methodToTest()
,因此这个答案确实验证了这两个调用是一起进行的。正在断言的捕获的List<String> values
将仅包含正在测试的两个值,不包含其他值。您也可以添加assertTrue(values.size == 2)
。如果这是您想要的,我会用一个 Hamcrest ...assertThat(values, contains("exception.message", "exception.detail"));
替换 3 个 assertTrue 语句methodToTest()
一次。它是方法参数ActionErrors errors
在内部调用了两次。