I have encountered what I assume might be a bug with Mockito, but was wondering if anyone else can shed light as to why this test doesn't work.
Basically, I have two objects, like this:
public class FirstObject { private SecondObject secondObject; public SecondObject getSecondObject() { return secondObject; } } public class SecondObject { private String name; public String getName() { return name; } }
The first object is mocked via annotation and the before method:
@Mock FirstObject mockedFirstObject; @Before public void setup() { MockitoAnnotations.initMocks(this); }
The second object is mocked in a method:
public SecondObject setupMockedSecondObject() { SecondObject secondObject = Mockito.mock(SecondObject.class); Mockito.when(secondObject.getName()).thenReturn("MockObject"); return secondObject; }
When thenReturn
contains a direct call to this method to setup and obtain a mock of the second object, it fails:
@Test public void notWorkingTest() { Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(setupMockedSecondObject()); Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject"); }
But, when the mock returned by the same method is assigned to a local variable, which is used in thenReturn
, it works:
@Test public void workingTest() { SecondObject mockedSecondObject = setupMockedSecondObject(); Mockito.when(mockedFirstObject.getSecondObject()).thenReturn(mockedSecondObject); Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject"); }
Are we doing something wrong or is this indeed a bug/limitation in Mockito? Is there a deliberate reason for this not working?
The thenReturn() methods lets you define the return value when a particular method of the mocked object is been called.
Mockito allows us to partially mock an object. This means that we can create a mock object and still be able to call a real method on it. To call a real method on a mocked object we use Mockito's thenCallRealMethod().
In Mockito, you can specify what to return when a method is called. That makes unit testing easier because you don't have to change existing classes. Mockito supports two ways to do it: when-thenReturn and doReturn-when . In most cases, when-thenReturn is used and has better readability.
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.
This is indeed a limitation of Mockito, and it is referenced in their FAQ:
Can I
thenReturn()
an inlinedmock()
?Unfortunately you cannot do this:
when(m.foo()).thenReturn(mock(Foo.class)); // ^
The reason is that detecting unfinished stubbing wouldn't work if we allow above construct. We consider is as a 'trade off' of framework validation (see also previous FAQ entry). However you can slightly change the code to make it working:
//extract local variable and start smiling: Foo foo = mock(Foo.class); when(m.foo()).thenReturn(foo);
The workaround, as mentioned, is to store the desired returned value in a local variable, like you have done.
The way I understand it is that Mockito validates the usage you make of it every time you call its methods. When another method is called during an on-going stubbing process, you are breaking its validation process.
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