我正在使用Mockito进行单元测试,并且遇到了以下异常。

org.mockito.exceptions.base.MockitoException:
`'setResponseTimeStampUtc'` is a *void method* and it *cannot* be stubbed with a *return value*!
Voids are usually stubbed with Throwables:
    doThrow(exception).when(mock).someVoidMethod();
***

If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
1. The method you are trying to stub is *overloaded*. Make sure you are calling the right overloaded version.
2. Somewhere in your test you are stubbing *final methods*. Sorry, Mockito does not verify/stub final methods.
3. A spy is stubbed using `when(spy.foo()).then()` syntax. It is safer to stub spies -
   - with `doReturn|Throw()` family of methods. More in javadocs for Mockito.spy() method.

这是实际的课程
@Repository
public class CardRepositoryImpl implements ICardRepository {
    @Autowired
    private OperationBean operation;

    @Override
    public OperationBean getCardOperation(final String cardHolderId, final String requestTimeStamp) {
        operation.setRequestTimeStampUtc(requestTimeStamp);
        operation.setResponseTimeStampUtc(DateUtil.getUTCDate());
        return operation;
    }
}

这是我编写的Test类。
@RunWith(MockitoJUnitRunner.class)
public class CardRepositoryImplUnitTestFixture_Mockito {
    @InjectMocks
    private CardRepositoryImpl cardRepositoryImpl;
    private OperationBean operationBean;

    @Before
    public void beforeTest() {
        MockitoAnnotations.initMocks(this);
    }
    @Test
    public void canGetCardOperation(){
        when(cardRepositoryImpl.getCardOperation("2", Mockito.anyString())).thenReturn(operationBean);

    }
}

这是return语句的问题,因为format()方法是最终方法。
public static String getUTCDate() {
    final TimeZone timeZone = TimeZone.getTimeZone("UTC");
    final Calendar calendar = Calendar.getInstance(timeZone);
    final SimpleDateFormat simpleDateFormat = new SimpleDateFormat("YYYY-MM-dd'T'HH:mm:ss.SSS'Z'");
    simpleDateFormat.setTimeZone(timeZone);
    return simpleDateFormat.format(calendar.getTime());
}

我该如何解决?

最佳答案

@InjectMocks
private CardRepositoryImpl cardRepositoryImpl;

when(cardRepositoryImpl.getCardOperation("2", Mockito.anyString()))
    .thenReturn(operationBean);
cardRepositoryImpl不是模拟的,因此您不能存根。使用@InjectMocks,您可以指示Mockito构造一个真实的CardRepositoryImpl,并用测试用例上的字段替换其私有字段和构造函数参数。您可能想改用间谍;再过一秒钟。

但是首先,为什么显示该错误消息? 因为它不是模拟,所以对cardRepositoryImpl.getCardOperation的调用发生在实际的CardRepositoryImpl实例上。 Mockito看到与operationBean(似乎确实是一个模拟物)的交互,将whenthenReturn视为与最近的模拟调用相对应,并错误地告诉您您正在使用返回值。

在CardRepositoryImpl的测试中,您不应嘲笑CardRepositoryImpl,也不应将其存根以返回值:除了Mockito可以工作之外,它不会进行任何测试。 为了使测试正常进行,您可能应该重新考虑需要存根的内容。

但是,当存根一个方法时,您可能想要存根同一类中的另一个方法。这可以通过一个间谍来完成:
@Test
public void canGetCardOperation(){
    CardRepositoryImpl spyImpl = spy(cardRepositoryImpl);
    when(spyImpl.getCardOperation(Mockito.eq("2"), Mockito.anyString()))
        .thenReturn(returnValue);
    // ...
    spyImpl.someOtherMethod();  // Any matching calls to getCardOperation from
                                // someOtherMethod will use the stub above.
}

旁注:存根时,您将相邻使用anyString"2"。当使用匹配器(如anyString)时,如果将其用作所有参数,则需要将其用于所有参数。 See more here.

07-27 18:44