处理HttpServletResponse时运行JerseyTest的问题

这是一个示例Resource类:

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

而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. } } 

除了使用@Context HttpServletRequest作为输入参数的资源外,我能够为所有其他资源运行泽西测试。 它给出了InternalServerErrorException: HTTP 500 Internal Server Error.

以下是堆栈跟踪:

 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.access$500(JerseyInvocation.java:88) at org.glassfish.jersey.client.JerseyInvocation$2.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$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.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$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.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) 

您的exception与HttpServletRequestnull的事实有关。

泽西文件说:

3.6。 使用@Context

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

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

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

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

  org.glassfish.jersey.test-framework jersey-test-framework-core 2.1   javax.servlet javax.servlet-api 3.0.1   org.glassfish.jersey.containers jersey-container-grizzly2-servlet 2.1  

现在你真的想告诉JerseyTest启动正确的测试服务器,为此你必须覆盖一个protected TestContainerFactory getTestContainerFactory()的方法protected TestContainerFactory getTestContainerFactory()请务必将替换为您的包的实际名称

 @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", "") ); } catch (ProcessingException e) { throw new TestContainerException(e); } catch (IOException e) { throw new TestContainerException(e); } } @Override public void stop() { this.server.stop(); } }; } }; } 

您还可以查看org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory以更好地实施工厂。

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

 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( HttpServletRequest.class, httpServletRequest) {}); } } 

泽西2:

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

所以最后我得到了解决方案(它接近最流行的答案,但变化很小):


的pom.xml

  2.22.1   org.glassfish.jersey.test-framework.providers jersey-test-framework-provider-inmemory ${jersey.version} test   org.glassfish.jersey.containers jersey-container-grizzly2-servlet ${jersey.version} test   javax.servlet javax.servlet-api 3.1.0 provided  

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

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

要测试Rest你需要这样做:

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

另请参阅peeskillet在此stackoverflow线程上答案: [link]

(目前列出的解决方案都没有为我工作)

好像很久以前这个问题一直存在。 作为@ 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找到一个例子。 要简单直接,您只需要在基础测试类中添加这些覆盖:

 // --- 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... 

(将YourResourceConfig替换为真实的。)

编辑:如果你使用泽西与jersey-spring3 ,你会发现上面的解决方案失败,因为没有你的所有春豆。 要解决这个问题:

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

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

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

并提供servlet上下文:

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