所以我有一些单元测试,我在嘲笑一些对象,并使用它们来编写测试。
我正在使用anyInt()
参数匹配器设置模拟对象。我想验证一个名为displayErrorMessage(String errorMsg)
的方法。此方法接受一个字符串,并将其输出到GUI。它接受的字符串在被发送到具有相关成员Id的显示方法之前被格式化。
我想以String格式再次使用参数匹配器将正确的错误消息传递给verify语句。
String.format("Member %d cannot borrow at this time.", anyInt());
我知道anyInt()
返回零。我可以手动验证displayErrorMessage(),假设这样,但这似乎不正确。
当前测试代码:
@Test
public void borrowingRestrictedWhenCardSwipedHasExceededFineLimit() throws Exception {
when(memberDAO.getMemberByID(anyInt())).thenReturn(member);
when(member.hasReachedFineLimit()).thenReturn(true);
ctl.initialise();
ctl.cardSwiped(anyInt());
String errorMessage = "Member %d cannot borrow at this time.";
errorMessage = String.format(errorMessage, anyInt());
verify(ui).displayErrorMessage(errorMessage);
}
此验证适用于这种情况:
verify(ui).displayErrorMessage("Member 0 cannot borrow at this time.");
如果我接近这个错误,那么更好的办法是什么?
答案 0 :(得分:1)
由于这个解释稍微长一点,这里有一个答案......
当需要匹配时,anyInt()用作参数。主要有两种情况:
when( myMock.someMethod( anyInt() ).thenReturn( x );
这使myMock在调用someMethod时返回“x” - 无论实际的int是什么。所以......
myMock.someMethod( 12 ) // will return x
myMock.someMethod( -180 ) // will return x
myMock.someMethod( 42 ) // will return x
// etc. ANY int parameter you give, will lead to x, since you told Mockito so in the when statement.
使用它的另一种方法是验证:
verify(myMock, times(1)).someMethod( anyInt() );
如果不使用任何int调用someMethod,则只会抛出错误。如果它被调用12或-180或42或1或2或3等,这将是正常的(只要它被称为一次 - 每个int不一次,但总共一次。)
当然anyInt()有一个int值,因为它必须放在int的位置,但我会完全忽略该值而不再依赖它。
最后调用真实方法时,不应该使用anyInt()而应该使用实际值,因为这样可以提供更多控制。在你的情况下,我根本不会使用anyInt(),说实话:
@Test
public void borrowingRestrictedWhenCardSwipedHasExceededFineLimit() throws Exception {
when(memberDAO.getMemberByID(42)).thenReturn(member);
when(member.hasReachedFineLimit()).thenReturn(true);
ctl.initialise();
ctl.cardSwiped(42);
String errorMessage = "Member %d cannot borrow at this time.";
errorMessage = String.format(errorMessage, 42);
verify(ui).displayErrorMessage(errorMessage);
}
为什么呢?因为这样你可以肯定,当调用ctl.cardSwiped
时,它实际上会使用memberDAO.getMemberByID
调用的参数。使用anyInt()你不能。例如,ctl.cardSwiped
中可能存在错误:
memberDao.getMemberById( parameter - 1);
当你的时间为anyInt()
时,你的结果仍然是会员。
您知道您的测试用例将给出42作为参数,并且仅在给出42时,您想要返回该成员。因此,您测试给定的参数实际上用于调用内部(memberDao)对象。
所以,至少打电话给ctl。使用实数而不是anyInt,最好甚至替换所有anyInt()调用,因为它们实际上并没有改善你的测试用例,但实际上降低了测试的质量。
使用anyInt并不意味着测试证明任何int都可以工作。什么内注使用是你的工作要知道。例如,是否允许使用负数?零?等
编辑:因为它已经在另一个答案中提出了......是的,当然另一种可能性是“愚蠢地”错误信息,它不需要实际的ID。问题是:错误消息是否重要?那里的身份重要吗?我猜是的,但这取决于用例。因此,如果确切的错误消息很重要,您将必须验证确切的错误消息 - 并在错误消息发生更改时调整您的测试。但这完全没问题,测试是为了确保特定的行为 - 如果确切的错误消息很重要,它是否是特定行为的一部分,必须进行测试。如果这种行为发生变化,那么单元测试的工作就是喊“Boo-Hoo,那种方法不再做它应该做的了。”。这就是单元测试的用途。
如果特定错误消息不重要但重要的是它包含id,那么您可以对其进行验证(使用contains
或ArgumentCaptor
)。
如果重要的是调用错误方法,无论实际消息如何,那么验证anyString()并完成它。
答案 1 :(得分:0)
doAnswer(new Answer<Void>() {
public Void answer(InvocationOnMock invocation) throws Throwable {
String msg = (String) args[0];
//Asserting the arguments with which mock method was invoked
Assert.assertEquals("expected", msg);
return null;
}
}).when(ui).displayErrorMessage(any(String.classs));
接口可用于与模拟以及调用其方法的参数进行交互。
{{1}}