java 处理 HttpServletResponse 时运行 JerseyTest 的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17973277/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-01 19:45:03  来源:igfitidea点击:

Problems running JerseyTest when dealing with HttpServletResponse

javarestjakarta-eejerseyjax-rs

提问by user2638465

Here is a sample Resource class:

这是一个示例资源类:

@Path("/resource") 
public class SomeResource { 
    @GET 
    @Produces({MediaType.APPLICATION_XML}) 
    public String someMethod(@QueryParam("param1") String param1, ..., @Context HttpServletRequest request) { 
            String remoteUser = request.getRemoteAddr(); 
            // Business logic here. 
            return response; 
    } 
} 

And the JerseyTest for the resource:

以及资源的 JerseyTest:

public class TestSomeResource extends JerseyTest    { 
    @Override 
    protected Application configure() { 
            enable(TestProperties.LOG_TRAFFIC); 
            return new ResourceConfig(SomeResource.class); 
    } 

    @Test 
    public void testXMLResponse()   { 
            String response = target("resource") 
                            .queryParam("param1", param1) 
                            // More parameters here. 
                            .request() 
                            .accept(MediaType.APPLICATION_XML) 
                            .get(String.class); 
            // Some assertions on response. 
    } 
} 

I am able to run jersey tests for all other resources except the ones using @Context HttpServletRequestas an input parameter. It gives a InternalServerErrorException: HTTP 500 Internal Server Error.

除了@Context HttpServletRequest用作输入参数的资源之外,我能够对所有其他资源运行球衣测试。它给出了一个InternalServerErrorException: HTTP 500 Internal Server Error.

Following is the stacktrace:

以下是堆栈跟踪:

javax.ws.rs.InternalServerErrorException: HTTP 500 Internal Server Error 
    at org.glassfish.jersey.client.JerseyInvocation.convertToException(JerseyInvocation.java:904) 
    at org.glassfish.jersey.client.JerseyInvocation.translate(JerseyInvocation.java:749) 
    at org.glassfish.jersey.client.JerseyInvocation.access0(JerseyInvocation.java:88) 
    at org.glassfish.jersey.client.JerseyInvocation.call(JerseyInvocation.java:650) 
    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:421) 
    at org.glassfish.jersey.client.JerseyInvocation.invoke(JerseyInvocation.java:646) 
    at org.glassfish.jersey.client.JerseyInvocation$Builder.method(JerseyInvocation.java:375) 
    at org.glassfish.jersey.client.JerseyInvocation$Builder.get(JerseyInvocation.java:275) 
    at com.mysample.TestSomeResource.testXMLResponse(TestSomeResource.java:15) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
    at java.lang.reflect.Method.invoke(Method.java:597) 
    at org.junit.runners.model.FrameworkMethod.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.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27) 
    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.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access
<dependency>
    <groupId>org.glassfish.jersey.test-framework</groupId>
    <artifactId>jersey-test-framework-core</artifactId>
    <version>2.1</version>
</dependency>
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.0.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-grizzly2-servlet</artifactId>
    <version>2.1</version>
</dependency>
0(ParentRunner.java:53) at org.junit.runners.ParentRunner.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)

回答by lpiepiora

You exception is related to the fact that the HttpServletRequestis null.

您的例外是有关的事实HttpServletRequestnull

Jersey documentation says:

泽西岛文档说:

3.6. Use of @Context

Previous sections have introduced the use of @Context. Chapter 5 of the JAX-RS specification presents all the standard JAX-RS Java types that may be used with @Context.

When deploying a JAX-RS application using servletthen ServletConfig, ServletContext, HttpServletRequest and HttpServletResponse are available using @Context.

3.6. @Context 的使用

前面几节介绍了@Context 的使用。JAX-RS 规范的第 5 章介绍了可以与 @Context 一起使用的所有标准 JAX-RS Java 类型。

使用 servlet部署 JAX-RS应用程序时,可以使用 @Context使用ServletConfig、ServletContext、HttpServletRequest 和 HttpServletResponse。

I'm guessing that you use jersey-test-framework-provider-grizzly2which doesn't support it.

我猜你使用的jersey-test-framework-provider-grizzly2不支持它。

If you want to have access to HttpServletResponseremove that dependency and add:

如果您想访问HttpServletResponse删除该依赖项并添加:

@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
    return new TestContainerFactory() {
        @Override
        public TestContainer create(final URI baseUri, final ApplicationHandler application) throws IllegalArgumentException {
            return new TestContainer() {
                private HttpServer server;

                @Override
                public ClientConfig getClientConfig() {
                    return null;
                }

                @Override
                public URI getBaseUri() {
                    return baseUri;
                }

                @Override
                public void start() {
                    try {
                        this.server = GrizzlyWebContainerFactory.create(
                                baseUri, Collections.singletonMap("jersey.config.server.provider.packages", "<your-java-package>")
                        );
                    } catch (ProcessingException e) {
                        throw new TestContainerException(e);
                    } catch (IOException e) {
                        throw new TestContainerException(e);
                    }
                }

                @Override
                public void stop() {
                    this.server.stop();
                }
            };

        }
    };
}

Now you actually want to tell JerseyTest to start the right test server, to do that you have to override a method protected TestContainerFactory getTestContainerFactory(). Please be sure to replace <your-java-package>with the actual name of your package.

现在您实际上想要告诉 JerseyTest 启动正确的测试服务器,为此您必须覆盖一个方法protected TestContainerFactory getTestContainerFactory()请务必替换<your-java-package>为您的包的实际名称

public abstract class AbstractIntegrationTest extends AbstractJerseyTest {

    protected HttpServletRequest httpServletRequest;

    @Override
    protected void configure(final ResourceConfig config) throws Exception {
        // create a mock and inject it via singleton provider
        httpServletRequest = mock(HttpServletRequest.class);
        config.getSingletons().add(
                new SingletonTypeInjectableProvider<Context, HttpServletRequest>(
                        HttpServletRequest.class, httpServletRequest) {});
    }

}

You can also check org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactoryfor better implementation of the factory.

您还可以检查org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory工厂的更好实现。

回答by Alexey Gavrilov

You can also inject a mocked HttpServletRequest object in the configure method. Here is an Jersey 1 example:

您还可以在 configure 方法中注入一个模拟的 HttpServletRequest 对象。这是一个 Jersey 1 示例:

final HttpServletRequest request = mock(HttpServletRequest.class);
resourceConfig.register(new AbstractBinder() {
                            @Override
                            protected void configure() {
                                bind(request).to(HttpServletRequest.class);
                            }
                        });

Jersey 2:

泽西2:

<properties>    
  <jersey.version>2.22.1</jersey.version>
</properties>

    <dependency>
        <groupId>org.glassfish.jersey.test-framework.providers</groupId>
        <artifactId>jersey-test-framework-provider-inmemory</artifactId>
        <version>${jersey.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-grizzly2-servlet</artifactId>
        <version>${jersey.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
        <scope>provided</scope>
    </dependency>

回答by Alexey Alexeenka

So finally I get working solution (It close to most popular answer but with small changes):

所以最后我得到了工作解决方案(它接近最受欢迎的答案,但有一些小的变化):



pom.xml

pom.xml

import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.grizzly2.servlet.GrizzlyWebContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.ServerProperties;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.JerseyTest;
import org.glassfish.jersey.test.TestProperties;
import org.glassfish.jersey.test.spi.TestContainer;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.Application;
import java.io.IOException;
import java.net.URI;
import java.util.Collections;

public abstract class RestTest extends JerseyTest {

    @Override
    protected Application configure() {
        enable(TestProperties.LOG_TRAFFIC);
        return new ResourceConfig();
    }

    abstract protected String getRestClassName();

    @Override
    protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
        return new TestContainerFactory() {
            @Override
            public TestContainer create(URI baseUri, DeploymentContext deploymentContext) {
                return new TestContainer() {
                    private HttpServer server;

                    @Override
                    public ClientConfig getClientConfig() {
                        return null;
                    }

                    @Override
                    public URI getBaseUri() {
                        return baseUri;
                    }

                    @Override
                    public void start() {
                        try {
                            this.server = GrizzlyWebContainerFactory.create(
                                    baseUri, Collections.singletonMap(ServerProperties.PROVIDER_CLASSNAMES, getRestClassName())
                            );
                        } catch (ProcessingException | IOException e) {
                            throw new TestContainerException(e);
                        }
                    }

                    @Override
                    public void stop() {
                        this.server.shutdownNow();

                    }
                };
            }
        };
    }

}


Add following abstract class to application:

将以下抽象类添加到应用程序:

import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Paths;

import static org.junit.Assert.assertEquals;

public class YourRestTest extends RestTest {

    private static final Logger LOG = LoggerFactory.getLogger("TestLog");

    @Override
    protected String getRestClassName() {
        return "com.app.rest.YourRest";
    }


    @Test
    public void test() throws URISyntaxException, IOException {
        String ttt = new String(Files.readAllBytes(Paths.get(YourRestTest.class.getResource("/rest_resource/ttt.json").toURI())));
        Response response = target("/xxx").path("/yyyy").request().post(Entity.entity(ttt, "application/json"));
        assertEquals(Response.Status.OK.getStatusCode(), response.getStatus());
    }
}

And to test Rest you need do like this:

要测试 Rest,您需要这样做:

// --- For Servlet-based test container --- begins ---

@Override
protected DeploymentContext configureDeployment() {
    return ServletDeploymentContext.forServlet(new ServletContainer(new YourResourceConfig())).build();
}

@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
    return new GrizzlyWebTestContainerFactory();
}

// --- For Servlet-based test container --- ends ---

// other stuff...

回答by NS du Toit

Also see peeskillet'sanswers on this stackoverflow thread: [link]

另请参阅此 stackoverflow 线程上的peeskillet答案:[链接]

(none of the currently listed solutions worked for me)

(目前列出的解决方案都不适合我)

回答by fwonce

Seems like this problem has been there since a long time ago. As @lpiepiora's explaination, we need a Servlet-based test container. And there already is one in jersey-test-framework-provider-grizzly2(don't know if there is it when the question posted), which is GrizzlyWebTestContainerFactory, and it requires a different DeploymentContext. Pull the newest git and you'll find an example in test-framework/providers/grizzly2/src/test/java/org/glassfish/jersey/test/grizzly/web/GrizzlyWebTest.java. To be straight and simple, you just need to add these overrides in your base test class:

好像这个问题很久以前就存在了。正如@lpiepiora 的解释,我们需要一个基于 Servlet 的测试容器。并且已经有一个jersey-test-framework-provider-grizzly2不知道发布问题时是否有),即GrizzlyWebTestContainerFactory,它需要一个不同的DeploymentContext. 拉取最新的 git,你会在test-framework/providers/grizzly2/src/test/java/org/glassfish/jersey/test/grizzly/web/GrizzlyWebTest.java. 为了直接和简单,您只需要在基本测试类中添加这些覆盖:

@Override
protected DeploymentContext configureDeployment() {
    return ServletDeploymentContext
            .servlet(new ServletContainer(new YourResourceConfig()))
            .addListener(ContextLoaderListener.class)
            .contextParam("contextConfigLocation", "classpath:applicationContext.xml")
            .build();
}

(Replace YourResourceConfigwith your real one.)

(换成YourResourceConfig你的真人。)

EDIT:If you use Jersey with jersey-spring3, you will find the solution above fails because of the absence of all your Spring beans. To fix it:

编辑:如果您将 Jersey 与 一起使用jersey-spring3,您会发现上述解决方案由于缺少所有 Spring bean 而失败。要解决这个问题:

TestSomeResource() {
    super(new GrizzlyWebTestContainerFactory());
}

回答by Serhiy Palamarchuk

The easier way is to provide correct factory in a test constructor:

更简单的方法是在测试构造函数中提供正确的工厂:

@Override
protected DeploymentContext configureDeployment() {
    return ServletDeploymentContext.forPackages("...").build(); // or other builder method
}

and provide servlet context:

并提供 servlet 上下文:

##代码##