Reputation: 98
Question first: How can I inject a mock (or real?) HttpServletResponse during my unit tests for CXF JAX-RS service endpoints?
Example of how our services are setup (note I have no control/authority to alter non-test structures):
package services.example;
import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
@RestController
@Path("/base")
@Produces(MediaType.APPLICATION_JSON_VALUE);
public class ExampleService {
@Autowired
SomeInjectedService injectedService;
@POST
@Path("/endpoint")
public Object testEndpoint(Object exampleInput, @Context HttpServletResponse response) {
if (exampleInput.someMethod != null) {
// Exception thrown here during tests, response is null!!!
response.setStatus(301);
return exampleInput;
}
return new injectedService.returnOutputFromInput(exampleInput);
}
}
Test class:
package test.services.example
// A gazillion imports. Mockito, JUnit, Hamcrest, Javax.ws.rs, org.apache.cxf, Jackson providers.
public class testExampleService {
@Mock
private HttpServletResponse mockResponse; // Should I do this?
@Mock
SomeInjectedService mockInjectionService;
@InjectMocks
ExampleService service = new ExampleService();
@Before
public void setUpStuff() {
MockitoAnnotations.initMocks(this);
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(ExampleService.class);
List<Object> providers = new ArrayList<Object>;
JacksonJsonProvider provider = new JacksonJsonProvider();
providers.add(provider);
sf.setProviders(providers);
sf.setResourceProvider(ExampleService.class, new SingletonResourceProvider(service, true));
sf.setAddress("local://someuri");
// This is where I'm trying to set up my injected Response context. Help?
sf.setInvoker(new Invoker() {
Invoker jarsInvoker = new JAXRSInvoker();
@Override
public Object invoke(Exchange exchange, Object o) {
// What goes in here? I've seen an example for setting a mock
// Request context, but no for a Response. Here's my current
// (broken) attempt to do this...
exchange.getInMessage().put(AbstractHTTPDestination.HTTP_RESPONSE, mockResponse);
return jarsInvoker.invoke(exchange, o);
}
});
}
@Test
public void testEndpointShouldReturn301() {
List<Object> providers = new ArrayList<Object>();
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
providers.add(provider);
WebClient client = WebClient.create("local://someuri", providers);
WebClient.getConfig(client)
.getRequestContext()
.put(LocalConduit.DIRECT_DISPATCH, Boolean.TRUE);
// Exception thrown here, Response context doesn't get injected!
client.path("/base/endpoint");
SomeTestObject obj = new SomeTestObject();
Response response = client.type(MediaType.APPLICATION_JSON).post(obj);
// Never gets run because an exception was thrown :(
assertThat(response.getStatus(), is(301));
}
}
It's possible that I'm doing a couple things wrong here, but I'm hoping that I just need the right "magic" going in inside my custom Invoker in order to properly inject an HttpServletResponse to my endpoint. I'll note that on my endpoints that do not have an injected Context, tests work correctly (when I remove my custom invoker bit).
Upvotes: 0
Views: 3010
Reputation: 71
You don't have to initialize Example service with constructor, just keep this:
@InjectMocks
ExampleService service;
If you want to test @Path("/endpoint"), then it's right what do you do but weird. If you want to test YOUR code, just do like this:
@Test
public void testEndpointShouldReturn301() {
service.testEndpoint(someObject, mockResponse);
assertThat(response.getStatus(), is(301));
}
Upvotes: 1