Reputation: 371
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
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
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