mock nested method calls using mockito

JavaMethodsJunitMockingMockito

Java Problem Overview


I have got 4 classes lets says A, B, C, D each calling on methods from another one.

now I have mocked class A, and want to mock a method using mockito

A a = Mockito.mock(A.class);

and want to get "foo" on recursive method calls like

a.getB().getC().getD() should return "foo"

I tried

> when(a.getB().getC().getD()).thenReturn("foo");

but got nullPointerException

then I tried

> doReturn("foo").when(a.getB().getC().getD());

then I got org.mockito.exceptions.misusing.UnfinishedStubbingException:

I know I can create objects of B, C and D, or can even write something like

> B b = mock(B.class) or A.setB(new B())

and so on.

But can't I do that in a single shot? Any help would be appreciated.

Java Solutions


Solution 1 - Java

Adding RETURNS_DEEP_STUBS did the trick:

A a = Mockito.mock(A.class, Mockito.RETURNS_DEEP_STUBS);

Solution 2 - Java

The answer by Abhijeet is technically correct, but it is important to understand: you should not be doing this.

Your "production" code is heavily violating the Law of Demeter: your class A should not know that it has to get a B to get a C to get a D.

That simply leads to super tight coupling between all these classes. Not a good idea.

In that sense: you should see the fact that you need to do special things here to get your test working as an indication that your production code does something that is out of the normal.

So, instead of "fixing" your test setup, consider addressing the real problem. And that is the design of your production code!

And for the record: getB().getC().getD() is not a "recursive" call; it is more of a "fluent" chaining of method calls. And as said: that is not a good thing.

Solution 3 - Java

Try by creating mock of each of the nested object and then mock the individual method called by each of these object.

If the target code is like:

public Class MyTargetClass {

    public String getMyState(MyClass abc){

       return abc.getCountry().getState();
    }
}

Then to test this line we can create mocks of each of the individual nested objects like below:

public Class MyTestCase{

@Mock
private MyTargetClass myTargetClassMock;

@Mock
private MyClass myclassMockObj;

@Mock
private Country countryMockObj;

@Before
public void setUp() throws Exception {
	MockitoAnnotations.initMocks(this);
}

    @Test
    public void test01(){

       when(myclassMockObj.getCountry()).thenReturn(countryMockObj);
       when(countryMockObj.getState()).thenReturn("MY_TEST_STATE");
       Assert.assertEquals("MY_TEST_STATE", myTargetClassMock.getMyState(myclassMockObj));
    }
}

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
QuestionAbhijeetView Question on Stackoverflow
Solution 1 - JavaAbhijeetView Answer on Stackoverflow
Solution 2 - JavaGhostCatView Answer on Stackoverflow
Solution 3 - JavaNagsView Answer on Stackoverflow