Reputation: 11486
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
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
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
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 usewhen(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:
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);
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
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
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
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