Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 898
Arun Avatar asked Feb 12 '16 21:02

Arun


People also ask

How do you return a void test?

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.

How to do Mockito for void methods?

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.

How do you throw an exception in the void method?

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.


1 Answers

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

like image 169
Jeff Bowman Avatar answered Sep 19 '22 17:09

Jeff Bowman