I am having some difficulty mocking out the necessary dependencies for some unit tests. I suspect I am not correctly understanding how to use the Mockito when().thenReturn().
Here is (hopefully the relevant) part of the code for the service I want to test:
@Singleton
public class AppointmentService {
private DataConnector connector;
@Inject
public AppointmentService(DataConnector connector) {
this.connector = connector;
}
public Appointment getAppointment(UriInfo uriInfo, String id) {
HttpResponse response = connector.getAppointment(id);
return validateResponse(response, uriInfo);
}
protected Appointment validateResponse(HttpResponse response, UriInfo uriInfo) {
try {
AppointmentWrapper appointmentWrapper = JacksonJsonUtility.readValue(response.getInputStream(), AppointmentWrapper.class);
if(appointmentWrapper.getAppointment()!=null) {
return appointmentConverterHelper(appointmentWrapper.getAppointment(), uriInfo.getPath());
}
} catch(IOException e) {
throw new ResponseParsingException("IOException: " + e.getMessage());
}
}
protected Appointment appointmentConverterHelper(ExternalAppointmentModel appointmentDto, String uriPath) {
if (appointmentDto == null) {
throw new BrickworkQueryException("Got an invalid appointment object from Brickwork!");
}
Customer customer = new Customer(new Name(appointmentDto.getCustomer().getName()),
appointmentDto.getCustomer().getEmail(),
String.valueOf(appointmentDto.getCustomer().getCode()));
return new Appointment(
appointmentDto.getId(),
customer);
}
}
My understanding is that my unit test for this method should look something like this:
public class AppointmentServiceTest {
private UriInfo mockUriInfo;
private HttpResponse mockHttpResponse;
@Mock
private DataConnector mockDataConnector;
@InjectMocks
private AppointmentService appointmentService;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mockUriInfo();
mockHttpResponse();
}
private void mockUriInfo() {
mockUriInfo = mock(UriInfo.class);
when(mockUriInfo.getRequestUri()).thenReturn(
URI.create("http://localhost:8080"));
}
private void mockHttpResponse() {
mockHttpResponse = mock(HttpResponse.class);
when(mockHttpResponse.getInputStream()).thenReturn(
IOUtils.toInputStream("{\"appointment\":{}}"));
}
@Test
public void testGetAppointment() throws Exception {
when(mockDataConnector.getAppointmentById(Mockito.anyString())).
thenReturn(mockHttpResponse);
when(appointmentService.validateResponse(Mockito.any(HttpResponse.class), Mockito.any(UriInfo.class))).
thenReturn(new Appointment());
appointmentService.getAppointment(mockUriInfo, "12345");
verify(mockDataConnector).getAppointment(Mockito.anyString());
}
}
When I run my test I get a NullPointerException in the appointmentConverterHelper method when trying to call appointmentDto.getCustomer(), which is understandably empty. As the code is running now, it seems to me that I will need to return an InputStream that contains a fully valid Appointment in my mockHttpResponse. Since I have when(appointmentService.validateResponse(mockHttpResponse, mockUriInfo)).thenReturn(new Appointment());
shouldn't that pick up the validateResponse
call and return the empty Appointment object rather than actually running validateResponse?
For reference, here is the stack trace on the Exception - line 140 of AppointmentServiceTest is the when
statement above. Line 176 of the AppointmentsService is the JacksonJsonUtility.readValue(response.getInputStream(), AppointmentWrapper.class);
line at the very beginning of the validateResponse
method:
java.lang.NullPointerException
at com.nike.appointmentservice.service.AppointmentsService.validatedResponse(AppointmentsService.java:176)
at com.nike.appointmentservice.service.AppointmentsServiceTest.testGetAppointmentById(AppointmentsServiceTest.java:140)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)```