使用 DropWizard 对 JAX-RS 端点执行单元测试时无法挂起异步请求的连接

Unable to suspend a connection of an asynchronous request while executing an unit test for a JAX-RS endpoint using DropWizard

我正在尝试为部署在 Dropwizard 中的 JAX-RS 资源编写单元测试,但我收到 javax.ws.rs.ProcessingException。

我已经写下了我尝试过的代码。

以下界面位于项目 api 文件夹结构中。

@Path("/doPostRequest")
public interface SomeResource {

    @POST 
    @Consumes({ "application/json" })
    @Produces({ "application/json" })
    void checkAndDoPostRequest(
        @Suspended SomeResponse response,
        @Valid SomeDetailsClass  someDetailsClassObject;
    );
}

我在项目结构的服务文件夹中有一个class实现这个接口,如下所示。

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));
    }
}

我之前通过扩展 JerseyTest class 并使用目标方法向该端点发送请求来为端点编写单元测试。但是对于 dropwizard 我不是很确定。

此外,这个端点需要两个对象,即在上面的接口中,"checkAndDoPostRequest" 方法需要两个对象,我不确定如何使用 "target" 方法发送这两个对象JerseyTest.

这是我尝试过的单元测试。

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;
    }

}

当我尝试 运行 上述测试用例时,出现以下异常

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.run(ServerRuntime.java:334)
at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
at org.glassfish.jersey.internal.Errors.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.call(JerseyInvocation.java:684)
at org.glassfish.jersey.client.JerseyInvocation.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.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.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.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access[=13=]0(ParentRunner.java:58)
at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.mockito.internal.runners.DefaultInternalRunner.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.run(ServerRuntime.java:326)
... 49 more

我尝试在单元测试中附加 "async()" 函数,与下面相同

public void testPostRequest() {
        Client client = resources.client();
        resources.getJerseyTest().target(URL).request().async()
            .post(Entity.entity(buildDetailsObject(), 
            MediaType.APPLICATION_JSON_TYPE));
    }

但是上面的实现只是阻止了处理异常,但没有运行测试正确,即请求没有到达端点。

有人可以帮忙吗。

我遇到了同样的问题。 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.

您应该在构建资源规则时使用以下行,当然还要添加 Grizzly 依赖项。

setTestContainerFactory(new GrizzlyWebTestContainerFactory())

问题中有代码示例和更多信息。