Arun
Arun

Reputation: 2342

MockitoException - is a *void method* and it *cannot* be stubbed with a *return value*!

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?

Upvotes: 13

Views: 29342

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95654

@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.

Upvotes: 5

Related Questions