Reputation: 302
Am trying to write a unit test for a JAX-RS resource deployed in Dropwizard but I am getting a javax.ws.rs.ProcessingException.
I have written down the code that I have attempted.
The below interface is placed within the project api folder structure.
@Path("/doPostRequest")
public interface SomeResource {
@POST
@Consumes({ "application/json" })
@Produces({ "application/json" })
void checkAndDoPostRequest(
@Suspended SomeResponse response,
@Valid SomeDetailsClass someDetailsClassObject;
);
}
I have a class implementing this interface in the service folder of the project structure as shown below.
public class SomeResourceImpl implements SomeResource {
private SomeProcessor someProcessor;
@Inject
public SomeResourceImpl(final
SomeProcessor someProcessor) {
this.someProcessor = someProcessor;
}
@Override
@RolesAllowed("read")
public void checkAndDoPostRequest(
SomeResponse response,
SomeDetailsClass someDetailsClassObject) {
response.resume(someProcessor.doProcess(someDetailsClassObject));
}
}
I have previously written Unit tests for endpoints by extending the JerseyTest class and using the target method to send a request to this endpoint. But in the case of dropwizard I am not entirely sure.
Moreover, this endpoint requires two objects, i.e., in the above interface the "checkAndDoPostRequest" method requires two objects and I am not sure how I can send both the objects using the "target" method in JerseyTest.
Here is the Unit test that I have attempted.
public class SomeResourceImplTest {
private ServiceLocator serviceLocator;
private static String final URL = "/doPostRequest";
@Rule
public ResourceTestRule resources = ResourceTestRule.builder()
.addResource(new SomeResourceImpl())
.build();
@Test
public void testPostRequest() {
Client client = resources.client();
resources.getJerseyTest().target(URL).request()
.post(Entity.entity(buildDetailsObject(),
MediaType.APPLICATION_JSON_TYPE));
}
private SomeDetailsClass buildDetailsObject() {
//code to build this object;
}
}
When I try to run the above test case, I get the following exception
javax.ws.rs.ProcessingException: Server-side request processing failed with an error.
at org.glassfish.jersey.test.inmemory.InMemoryConnector$InMemoryResponseWriter.failure(InMemoryConnector.java:167)
at org.glassfish.jersey.server.ServerRuntime$Responder.process(ServerRuntime.java:509)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:334)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:305)
at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1154)
at org.glassfish.jersey.test.inmemory.InMemoryConnector.apply(InMemoryConnector.java:275)
at org.glassfish.jersey.client.ClientRuntime.invoke(ClientRuntime.java:252)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation$1.call(JerseyInvocation.java:681)
at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
at org.glassfish.jersey.internal.Errors.process(Errors.java:228)
at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:444)
at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:681)
at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:437)
at org.glassfish.jersey.client.JerseyInvocation$Builder.post(JerseyInvocation.java:343)
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:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at io.dropwizard.testing.junit.ResourceTestRule$1.evaluate(ResourceTestRule.java:174)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner$1.run(DefaultInternalRunner.java:68)
at org.mockito.internal.runners.DefaultInternalRunner.run(DefaultInternalRunner.java:74)
at org.mockito.internal.runners.StrictRunner.run(StrictRunner.java:39)
at org.mockito.junit.MockitoJUnitRunner.run(MockitoJUnitRunner.java:161)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:678)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: javax.ws.rs.ProcessingException: Attempt to suspend a connection of an asynchronous request failed in the underlying container.
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:328)
at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
at org.glassfish.jersey.server.ServerRuntime$2.run(ServerRuntime.java:326)
... 49 more
I tried appending the "async()" function in the unit test identical to below
public void testPostRequest() {
Client client = resources.client();
resources.getJerseyTest().target(URL).request().async()
.post(Entity.entity(buildDetailsObject(),
MediaType.APPLICATION_JSON_TYPE));
}
But the above implementation simply prevents the processing exception but the doesn't run the test correctly i.e., the request doesn't hit the endpoint.
Can someone please help.
Upvotes: 2
Views: 494
Reputation: 174
I faced the same problem. There is a solution for it in this Github issue.
Looks like InMemoryConnector doesn't support endpoints that can be suspended and are async, so a new testing container is needed. You may need to try out the Grizzly test web server. I was able to swap it out and have my test cases pass.
You should use the following line when building the resource rule and of course add the Grizzly dependency.
setTestContainerFactory(new GrizzlyWebTestContainerFactory())
There is code sample and more information in the issue.
Upvotes: 2