I'm using Mockito for unit testingand I'm getting the following exception.
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.
Here is the actual class
@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;
}
}
this is the Test class I have written.
@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);
}
}
Is this an issue with the return statement since format() method is a final method.
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());
}
How can I resolve this?
Using the verify() method. Whenever we mock a void method we do not expect a return value that is why we can only verify whether that method is being called or not. Features of verify(): Mockito provides us with a verify() method which lets us verify whether the mock void method is being called or not.
Mockito provides following methods that can be used to mock void methods. doAnswer() : We can use this to perform some operations when a mocked object method is called that is returning void. doThrow() : We can use doThrow() when we want to stub a void method that throws exception.
To make a void method throw an exception, we use doThrow() . The exception we pass to the doThrow() is thrown when the mocked method is called.
@InjectMocks
private CardRepositoryImpl cardRepositoryImpl;
when(cardRepositoryImpl.getCardOperation("2", Mockito.anyString()))
.thenReturn(operationBean);
cardRepositoryImpl
is not a mock, so you can't stub it. With @InjectMocks
you are instructing Mockito to construct a real CardRepositoryImpl and have its private fields and constructor parameters substituted with fields on the test case. You'll probably want to use a spy instead; more on that in a second.
But first, why that error message? Because it's not a mock, the call to cardRepositoryImpl.getCardOperation
happens on an actual CardRepositoryImpl instance. Mockito sees the interactions with operationBean
(which does seem to be a mock), treats the when
and thenReturn
as corresponding with that most recent mock call, and erroneously tells you you're stubbing a void method (importantly, the wrong method) with a return value.
In a test for CardRepositoryImpl, you shouldn't be mocking CardRepositoryImpl, nor stubbing it to return values: This won't test anything, except that Mockito works. You should probably rethink what you need to stub in order for your test to work.
However, when stubbing one method, you might want to stub another method in the same class. This can be accomplished with a spy:
@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.
}
Side note: You use anyString
and "2"
adjacently while stubbing. When using Matchers like anyString
, you need to use them for all arguments if you use them for any arguments at all. See more here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With