Java 使用“when”作为验证

Java 使用“when”作为验证,java,mockito,Java,Mockito,我在数百个测试中使用了一种实用方法来模拟定制随机化器的返回值。以下是我的代码(高度人工)模型: interface CardRandomiser{ Card getCard(Suit suit); } void mockCard(Suit suit, Face face) { CardRandomiser rand = mock(CardRandomiser.class); when(rand.getCard(suit)).thenReturn(new Card(sui

我在数百个测试中使用了一种实用方法来模拟定制随机化器的返回值。以下是我的代码(高度人工)模型:

interface CardRandomiser{
    Card getCard(Suit suit);
}

void mockCard(Suit suit, Face face) {
    CardRandomiser rand = mock(CardRandomiser.class);
    when(rand.getCard(suit)).thenReturn(new Card(suit, face));
    Game.setCardRandomiser(rand);
}
然后可将其用作:

mockCard(Suit.CLUBS, Face.QUEEN);
Card card = pickACardAnyCard();
assertThat(card.getFace(), is(Face.QUEEN));
然而,这使得一些bug有点难以识别。如果被测试的方法错误地请求
Suit.HEARTS
,则mock返回null,断言正确地失败。但无法通过错误消息判断传递给mock的是什么

显然,我可以通过
验证
来处理这个问题。我可以将mock back从
mockCard
函数中传递出去,然后分别验证是否使用正确的值调用了is。但这确实会使测试断言变得杂乱无章,而这些断言与正在测试的内容并不真正相关。给定每次调用此方法时,我都指定一个预期的参数值,我更愿意将断言放在一个位置。请注意,这一切都发生在调用被测方法之前

理想情况下,我希望
when
语句在使用意外值调用时抛出异常。比如:

when(rand.getCard(suit)).thenReturn(new Card(suit, face));
when(rand.getCard(intThat(not(is(suit))))).thenThrow(new IllegalArgumentException());
当调用
getCard
时,这会起作用并停止测试,哪个更好。但它仍然不允许我证明什么是不正确的论点

我还使用
ArgumentCaptor
尝试了它,然后检查捕获的值。但很明显,它们是用于
verify
语句,而不是
when
语句


是否有一种标准的Mockito方法来实现这一点,或者我是否需要用
验证
语句来混乱我的测试?

您可以使用
然后answer
来配置Mockito answer,例如

private CardRandomiser mockCard(final Suit suit, final Face face) {
    CardRandomiser rand = mock(CardRandomiser.class);

    when(rand.getCard(any(Suit.class))).thenAnswer(new Answer<Card>() {
        @Override
        public Card answer(InvocationOnMock invocation) throws Throwable {
            if(!suit.equals(invocation.getArguments()[0])) {
                 throw new IllegalArgumentException(
                         String.format("Value %s passed, but mocked for %s", invocation.getArguments()[0], suit));
            }
            return new Card(suit, face);
        }
    });

    return rand;
}
private CardRandomiser模拟卡(最后一套西装,最后一张脸){
CardRandomiser rand=mock(CardRandomiser.class);
当(rand.getCard(any(Suit.class)),然后回答(new-Answer(){
@凌驾
公共卡应答(调用锁调用)抛出可丢弃{
如果(!suit.equals(invocation.getArguments()[0])){
抛出新的IllegalArgumentException(
String.format(“值%s已传递,但为%s模拟”,invocation.getArguments()[0],suit));
}
退回新卡(西装、脸);
}
});
返回兰特;
}

您可以使用
然后使用answer
配置mockito answer,例如

private CardRandomiser mockCard(final Suit suit, final Face face) {
    CardRandomiser rand = mock(CardRandomiser.class);

    when(rand.getCard(any(Suit.class))).thenAnswer(new Answer<Card>() {
        @Override
        public Card answer(InvocationOnMock invocation) throws Throwable {
            if(!suit.equals(invocation.getArguments()[0])) {
                 throw new IllegalArgumentException(
                         String.format("Value %s passed, but mocked for %s", invocation.getArguments()[0], suit));
            }
            return new Card(suit, face);
        }
    });

    return rand;
}
private CardRandomiser模拟卡(最后一套西装,最后一张脸){
CardRandomiser rand=mock(CardRandomiser.class);
当(rand.getCard(any(Suit.class)),然后回答(new-Answer(){
@凌驾
公共卡应答(调用锁调用)抛出可丢弃{
如果(!suit.equals(invocation.getArguments()[0])){
抛出新的IllegalArgumentException(
String.format(“值%s已传递,但为%s模拟”,invocation.getArguments()[0],suit));
}
退回新卡(西装、脸);
}
});
返回兰特;
}