blackpanther
blackpanther

Reputation: 11486

Mockito - difference between doReturn() and when()

I am currently in the process of using Mockito to mock my service layer objects in a Spring MVC application in which I want to test my Controller methods.

However, as I have been reading on the specifics of Mockito, I have found that the methods doReturn(...).when(...) is equivalent to when(...).thenReturn(...).

So, my question is what is the point of having two methods that do the same thing, or what is the subtle difference between the two?

Upvotes: 353

Views: 313999

Answers (6)

kairoslav
kairoslav

Reputation: 33

I've had the same kind of problem, but with a mocked class being null.

when(someService.getSomething(anyString()))
     .thenReturn(someResponse);

This code was producing the following exception:

java.lang.NullPointerException: Cannot invoke "SomeService.getSomething(String)" because "this.someService" is null

What helped me was that I found I was using the wrong @Test annotation from org.junit.Test instead of org.junit.jupiter.api.Test. The funny thing is, this test worked fine in CI.

Upvotes: 1

Cerdicipe
Cerdicipe

Reputation: 347

There are some rare situations that makes thenReturn not expecting the good type. For example when returning unresolved generic types:

class ObjectToTest {
    public ObjectToTest(ObjectToMock objectToMock) {
        objectToMock.getSomething().doSomething();
    }
}

class ObjectToMock {
    public Something<?> getSomething() {
        return new Something<>();
    }
}

class Something<T> {
    public void doSomething() { }
}

@Test
void testExample() {
    // GIVEN
    final Something<String> something = new Something<>();

    final ObjectToMock objectToMock = mock(ObjectToMock.class);

    // KO: Compile-time: Cannot resolve method 'thenReturn(Something<String>)
    when(objectToMock.getSomething()).thenReturn(something);

    // KO: Compile-time: Cannot resolve method 'thenReturn(Something<capture of ?>)'
    when(objectToMock.getSomething()).thenReturn((Something<?>) something);

    // KO: Compile-time: Inconvertible types; cannot cast 'Something<java.lang.String>' to 'Something<java.lang.Object>'
    when(objectToMock.getSomething()).thenReturn((Something<Object>) something);

    // OK but with a warning "Raw use of parameterized class 'Something'" 
    when(objectToMock.getSomething()).thenReturn((Something) something);

    // OK no warning
    doReturn(something).when(objectToMock).getSomething();

    // WHEN
    new ObjectToTest(objectToMock);

    // THEN
    verify(objectToMock, times(1)).getSomething();
}

As well said by contributers the method doReturn is not type-safe (expecting an Object type), thus the Java compiler cannot detect a bad type in compile-time. But it may prevent some warnings for specific use cases.

Upvotes: 0

user2493028
user2493028

Reputation:

The Mockito javadoc tells when to use doReturn() instead of when():

public static Stubber doReturn(Object toBeReturned)

Use doReturn() in those rare occasions when you cannot use when(Object).

Beware that when(Object) is always recommended for stubbing because it is argument type-safe and more readable (especially when stubbing consecutive calls).

Here are those rare occasions when doReturn() comes handy:

  1. When spying real objects and calling real methods on a spy brings side effects

    List list = new LinkedList();  List spy = spy(list);
    
    //Impossible: real method is called
    //so spy.get(0) throws IndexOutOfBoundsException (the list is yet empty)
    
    when(spy.get(0)).thenReturn("foo");
    
    //You have to use doReturn() for stubbing:
    doReturn("foo").when(spy).get(0);
    
  2. Overriding a previous exception-stubbing:

    when(mock.foo()).thenThrow(new RuntimeException());
    
    //Impossible: the exception-stubbed foo() method is called
    //so RuntimeException is thrown.
    when(mock.foo()).thenReturn("bar");
    
    //You have to use doReturn() for stubbing:
    doReturn("bar").when(mock).foo();
    

Above scenarios shows a tradeoff of Mockito's elegant syntax. Note that the scenarios are very rare, though. Spying should be sporadic and overriding exception-stubbing is very rare. Not to mention that in general overridding stubbing is a potential code smell that points out too much stubbing.

See examples in javadoc for Mockito class

Upvotes: 30

akcasoy
akcasoy

Reputation: 7215

Both approaches behave differently if you use a spied object (annotated with @Spy) instead of a mock (annotated with @Mock):

  • when(...) thenReturn(...) makes a real method call just before the specified value will be returned. So if the called method throws an Exception you have to deal with it / mock it etc. Of course you still get your result (what you define in thenReturn(...))

  • doReturn(...) when(...) does not call the method at all.

Example:

public class MyClass {
     protected String methodToBeTested() {
           return anotherMethodInClass();
     }

     protected String anotherMethodInClass() {
          throw new NullPointerException();
     }
}

Test:

@Spy
private MyClass myClass;

// ...

// would work fine
doReturn("test").when(myClass).anotherMethodInClass();

// would throw a NullPointerException
when(myClass.anotherMethodInClass()).thenReturn("test");

Upvotes: 368

Dawood ibn Kareem
Dawood ibn Kareem

Reputation: 79807

The two syntaxes for stubbing are roughly equivalent. However, you can always use doReturn/when for stubbing; but there are cases where you can't use when/thenReturn. Stubbing void methods is one such. Others include use with Mockito spies, and stubbing the same method more than once.

One thing that when/thenReturn gives you, that doReturn/when doesn't, is type-checking of the value that you're returning, at compile time. However, I believe this is of almost no value - if you've got the type wrong, you'll find out as soon as you run your test.

I strongly recommend only using doReturn/when. There is no point in learning two syntaxes when one will do.

You may wish to refer to my answer at Forming Mockito "grammars" - a more detailed answer to a very closely related question.

Upvotes: 342

vikingsteve
vikingsteve

Reputation: 40378

The latter alternative is used for methods on mocks that return void.

Please have a look, for example, here: How to make mock to void methods with mockito

Upvotes: 8

Related Questions