我正在使用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
(似乎确实是一个模拟物)的交互,将when
和thenReturn
视为与最近的模拟调用相对应,并错误地告诉您您正在使用返回值。在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.