13

Let's say I have an mock object, and I don't want to stub any of it's methods, but I want to stub a method of an object it returns. For example,

when(mockObject.method1()).thenReturn(returnValue)

is how it's normally done, but I'm looking for,

when(mockObject.method1().method2()).thenReturn(returnValue)

Is that possible? I get a NullPointerException if I do that. Currently I have stub the first method to return a mock object, and then using that returned mock object, stub the second method. However, these temporary mock objects are useless to me and after chaining many methods together, that results in a lot of useless mock objects.

EDIT: Actually, it's possible that chaining works, but my objects are causing the NPE. This code (the first line) is causing a NPE:

when(graphDb.index().getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

But this code works:

IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

So chaining didn't work for getNodeAutoIndexer() which returns an AutoIndexer object while it worked for getRelationshipAutoIndexer() which returns a RelationshipAutoIndexer. Both return values are mocked as follows:

nodeAutoIndexer = (AutoIndexer<Node>) mock(AutoIndexer.class);
relAutoIndexer = mock(RelationshipAutoIndexer.class);

So what could be causing the problem?

gsgx
  • 12,020
  • 25
  • 98
  • 149

1 Answers1

15

There is no problem at all.

Let's examine these 4 lines of code:

IndexManager indexManager = mock(IndexManager.class);
when(graphDb.index()).thenReturn(indexManager);
when(indexManager.getNodeAutoIndexer()).thenReturn(nodeAutoIndexer);
when(graphDb.index().getRelationshipAutoIndexer()).thenReturn(relAutoIndexer);

The first line creates a mock indexManager.

The second one tells the mock graphDb to return indexManager (the mock created at first line) when the index method is called.

The third one telle the mock indexManager (created at first line) to return nodeAutoIndexer when its getNodeAutoIndexer method is called.

And the last line calls graphDb.index(), which returns the mock indexManager (you told it to do that at line two), and asks this indexManager (which is the mock you created at first line) to return relAutoIndexer when its getRelationshipAutoIndexer method is called.

The last line works only because you told the mock graphDb what to return when its index method is called. If you had not done this before, the mock graphDb.index() method would have returned null and you would have had an NPE.

JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • 1
    Thanks. So let's say I have a long chain of functions, will I have to repeat this process of stubbing each function? There's no way of getting the code that's giving a NPE to work without stubbing index()? I feel like Mockito should somehow automatically stub those methods with mock objects based on the return types of the functions so that I don't have to bother stubbing functions I don't need directly. I only need those functions to get to other functions... – gsgx Oct 29 '11 at 16:11
  • 1
    No. The default return value is null for methods which return objects. IMHO, the problem you're having is a sign that you violate the law of Demeter : don't talk to strangers. – JB Nizet Oct 29 '11 at 16:25
  • 4
    Note that mockito offer a deep stub feature (`mock(LegacyType.class, RETURNS_DEEP_STUBS)`), but discourage its use because you might break _good design_ laws, such as the Law of Demeter. Please note also that this feature don't work yet with generic types, eg a List. – bric3 Oct 29 '11 at 18:29
  • Thanks Brice. I didn't know about that, and this actually could solve the OP's problem. – JB Nizet Oct 29 '11 at 18:33