67

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.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
Abhijeet Ahuja
  • 5,596
  • 5
  • 42
  • 50

3 Answers3

113

Adding RETURNS_DEEP_STUBS did the trick:

A a = Mockito.mock(A.class, Mockito.RETURNS_DEEP_STUBS);
Vishwa Ratna
  • 5,567
  • 5
  • 33
  • 55
Abhijeet Ahuja
  • 5,596
  • 5
  • 42
  • 50
  • 42
    Alternatively, if using annotations: `@Mock(answer = Answers.RETURNS_DEEP_STUBS)` – Andrey Nov 04 '17 at 18:49
  • 10
    From the documentation of RETURNS_DEEP_STUBS: "Good quote I've seen one day on the web: every time a mock returns a mock a fairy dies." – BitfulByte Feb 18 '19 at 15:50
  • 2
    Just to clarify, in @Andrey's comment, `answer` and `Answers` are exactly what you're supposed to type; it's not your mocked variable/class (I wasted a few minutes to realize that)! – Leponzo Apr 26 '21 at 18:11
26

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.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 29
    I completely agree with you. But sometimes to earn his bread and butter, a developer has to write unit test cases for legacy applications, not everyone is lucky to write production code again. – Abhijeet Ahuja Jan 19 '17 at 10:22
  • 12
    You're being excessively strict about the rules of OO, and it is not the only way you can dive in. Suppose you have a configuration object, you may group your configurations in nested classes (i.e. `connection`, `authentication`). Hence you may provide a fluent access to the fields by using nested properties, such as `configuration.connection.idlePingInterval`, or `configuration.authentication.privateKey` (ignore getters/setters). This was exactly my use case. This has nothing to do with *Demeter*, since this is a data class, rather than a behavioral preposition. – Buğra Ekuklu Jan 02 '19 at 21:20
  • 4
    Everything is fine when you know what you are doing. But a lot of people don't. They do things because they can, and nobody ever told them "that leads to this or that problem, so rather do it this way instead". And make no mistake: when you start to get sloppy on such rules, sooner or later you end up with a mess. Doesn't matter for code that gets thrown away after 6 months, but it does matter big time for code that exists for 5 or 10 or more years. – GhostCat Jan 03 '19 at 05:08
  • In my experience these types of dangerous tightly coupled designs are only safe to test once complex unit tests have been written for them. Otherwise you risk changing difficult-to-discover edge cases because you aggressively refactored before you were sure that you knew what was broken (if anything). I humbly disagree that your tests code should be equally ignorant of the inner workings of the code under test as the classes themselves. Often times the whole function of mocking is to remove implementation details of how an interface is implemented. – xaviersjs Apr 19 '21 at 21:29
  • see also: https://en.wikipedia.org/wiki/Mock_trainwreck – 0cd Dec 24 '21 at 12:28
5

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));
    }
}
Nags
  • 273
  • 1
  • 4
  • 16