Mockito: using a method in "thenReturn" to return a mock doesn't work

JavaUnit TestingMockingMockito

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

This is indeed a limitation of Mockito, and it is referenced in their FAQ: >### Can I thenReturn() an inlined mock()? > >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.

Solution 2 - Java

You can't use a method in thenReturn, but you can in thenAnswer Your code will be called after the when condition will occur, unlike any workaround based on thenReturn

Thus you could write:

@Test
public void nowWorkingTest() {
    Mockito.when(mockedFirstObject.getSecondObject()).thenAnswer(new Answer<Map>() {
        @Override
        public Map answer(InvocationOnMock invocation) {
            return setupMockedSecondObject();
        }
    });
    Assert.assertEquals(mockedFirstObject.getSecondObject().getName(), "MockObject");
}

Let find another example here

Solution 3 - Java

@Test
public void testAuthenticate_ValidCredentials() throws FailedToAuthenticateException {

	String username = "User1";
	String password = "Password";
	/*Configure Returning True with when...thenReturn configuration on mock Object - Q5*/
   //Write your code here
	assertTrue(authenticator.authenticateUser(username, password));
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLawrenceWeetmanView Question on Stackoverflow
Solution 1 - JavaTunakiView Answer on Stackoverflow
Solution 2 - Javauser1767316View Answer on Stackoverflow
Solution 3 - JavaGauravView Answer on Stackoverflow