IwantToKnow
IwantToKnow

Reputation: 371

NPE when calling a mocked object (Mockito)

I'm having problems calling a mocked method of an object that is returned by another mocked method of my mocked service.

In particular I want to mock the result of "builder.get()". But when "builder.get()" is called, I'm gettting a null pointer exception (builder is null).

My Controller looks like:

@RestController
public class MyController {

@Autowired
MyClientService myClientService;

@RequestMapping("/myMethod")
@Validated
public MyCustomResponse myMethod(@RequestParam String someId, @Valid @ModelAttribute("someParams") SomeHeaderParams someHeaderParams) {
    final String targetString = myClientService.buildTargetString("resource", someId + "/myMethod");
    final Map<String, String> headerMap = myClientService.getHeaderParams(someHeaderParams);

    Map<String, String> paramsMap = new HashMap<>();
    paramsMap.put("SOME_ID", someId);

    Invocation.Builder builder = myClientService.buildRequest(targetString, headerMap, paramsMap);
    final Response response = builder.get();
    return response.readEntity(MyCustomResponse.class);
}

}

And my Test looks like:

@RunWith(MockitoJUnitRunner.class)
public class MyControllerTests {

@Spy
@InjectMocks
MyController myControllerController;

@Mock
MyClientService myClientService;

SomeHeaderParams someHeaderParams;

@Before
public void init() {
    someHeaderParams = new SomeHeaderParams();
    someHeaderParams.setCommunicationLanguage("de");
    someHeaderParams.setCrId("123");
    someHeaderParams.setMemberUserId("qwe");
}

@Test

public void myTest() {
    MyCustomResponse myResponseMock = mock(MyCustomResponse.class);
    Response responseMock = mock(Response.class);
    Mockito.when(responseMock.readEntity(MyCustomResponse.class)).thenReturn(myResponseMock);

    Invocation.Builder builderMock = mock(Invocation.Builder.class);
    Mockito.when(builderMock.get()).thenReturn(responseMock);
    Mockito.when(myClientService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);
    MyCustomResponse response = myControllerController.myMethod("myBusinessId", someHeaderParams);
}

} This should not be too difficult but I didn't find any examples where the mocked method returned another Mock, I only found examples where it returns a String.

Upvotes: 0

Views: 2043

Answers (2)

Lorenzo Murrocu
Lorenzo Murrocu

Reputation: 688

The second row of myMethod(String someId, SomeHeaderParams someHeaderParams) in MyController class:

There is an invocation of the method myClientService.getHeaderParams(SomeHeaderParams): I don't see any mock configuration for that invocation, so it should return null, and when the buildRequest(String, Map, Map) method is called, it should recive a null as second argument. The matcher anyMap() is not met, and this is why it returns the default value, null, instead of the configured mock for the Invocation.Builder class.

The solution can be to include the following in your test:

Mockito.when(myClientService.getHeaderParams(Mockito.any(SomeHeaderParams.class))).thenReturn(new HashMap<String, String>());

Like this:

@Test
public void myTest() {
    MyCustomResponse myResponseMock = mock(MyCustomResponse.class);
    Response responseMock = mock(Response.class);
    Mockito.when(responseMock.readEntity(MyCustomResponse.class)).thenReturn(myResponseMock);

    Invocation.Builder builderMock = mock(Invocation.Builder.class);
    Mockito.when(builderMock.get()).thenReturn(responseMock);
    Mockito.when(myClientService.getHeaderParams(Mockito.any(SomeHeaderParams.class))).thenReturn(new HashMap<String, String>());
    Mockito.when(myClientService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);
    MyCustomResponse response = myControllerController.myMethod("myBusinessId", someHeaderParams);
}

Upvotes: 1

Lorenzo Murrocu
Lorenzo Murrocu

Reputation: 688

Using Mockito, you can configure your mocks to return anything you want, so you actually can configure a mock's method to return another mock.

Looking at the question's code, I see an important difference.

In the class MyController, the third row of the method a() is:

final Invocation.Builder builder = someService.buildRequest(targetString, someMap);

In the test class, seventh row of the test method, the mock is configured as follows:

Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap(), Mockito.anyMap())).thenReturn(builderMock);

So, the method used in MyController class is buildRequest(String, Map), but the mocked method is buildRequest(String, Map, Map), that is not the same method actually used by MyController.

It should work fine if you replace that row in your test with:

Mockito.when(someService.buildRequest(Mockito.anyString(), Mockito.anyMap())).thenReturn(builderMock);

Upvotes: 0

Related Questions