处理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与HttpServletRequest
为null
的事实有关。
泽西文件说:
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 }