2013-07-31 23 views
16

Oto klasa próbka zasobów:Problemy z uruchamianiem JerseyTest gdy ma do czynienia z HttpServletResponse

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

A JerseyTest dla zasobu:

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

jestem w stanie uruchomić testy jersey na wszystkich innych zasobów, z wyjątkiem te używające @Context HttpServletRequest jako parametru wejściowego. Daje InternalServerErrorException: HTTP 500 Internal Server Error.

Poniżej znajduje się 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.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) 
+0

Która linia 15 to 'TestSomeResource.java'? –

+0

To jest '.get (String.class)' wewnątrz 'testXMLResponse()'. Ogólnie rzecz biorąc, byłbym również szczęśliwy, gdybyś mógł wskazać mi dokumentację związaną z JerseyTest podczas pracy z '@Context HttpServletRequest'. Dzięki! – user2638465

Odpowiedz

21

Ty Wyjątkiem jest związane z faktem, że HttpServletRequest jest null.

dokumentacja Jersey mówi:

3,6. Korzystanie z @Context

Poprzednie sekcje wprowadziły użycie @Context. Rozdział 5 z specyfikacja JAX-RS przedstawia wszystkie standardowe typy JAX-RS Java , które mogą być używane z @Context.

Podczas wdrażania JAX Rs aplikacji przy serwlet następnie ServletConfig, ServletContext, HttpServletRequest i HttpServletResponse są dostępny poprzez @Context.

Zgaduję, że używasz jersey-test-framework-provider-grizzly2, która go nie obsługuje.

Jeżeli chcesz mieć dostęp do HttpServletResponse usunąć tę zależność i dodać:

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

Teraz rzeczywiście chcesz powiedzieć JerseyTest rozpocząć właściwą serwera testowego, aby to zrobić trzeba zastąpić metodę protected TestContainerFactory getTestContainerFactory(). Pamiętaj, aby zastąpić <your-java-package> rzeczywistą nazwą pakietu.

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

     } 
    }; 
} 

Możesz również sprawdzić org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory dla lepszego wdrożenia fabryki.

+0

Użyłem "pojemnika grizzly2", który obsługuje serwer JerseyTest. – user2638465

+0

Sprawdź moją zaktualizowaną odpowiedź, w ten sposób nadal możesz korzystać z Grizzly i powinno działać teraz. – lpiepiora

+0

Dzięki .. !!! Twoje rozwiązanie sprawdziło się u mnie. Wysłałem nawet koszulkę [forums] (http://jersey.576304.n2.nabble.com/Problems-running-JerseyTest-with-HttpServletResponse-td7580993.html), ale nikt nie odpowiedział. Niestety nie używałem maven, więc musiałem się bawić z kilkoma słoikami. – user2638465

11

Można również wstrzyknąć wyszydzony obiekt HttpServletRequest w metodzie configure. Oto Jersey 1 Przykład:

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

} 

Jersey 2:

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

Miał ten problem z Jersey 2. Pozwala to na mniej szczegółową klasę testową. Dzięki! – Rick

1

Więc rozwiązanie wreszcie dostaję pracę (Jest blisko do najbardziej popularnych odpowiedzi, ale z małymi zmianami):


pom.xml

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

Dodaj następujący abstrakcyjnej klasy do aplikacji:

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

        } 
       }; 
      } 
     }; 
    } 

} 

I przetestowania Rest trzeba zrobić tak:

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

Dzięki za podzielenie się resztą. – Drew

-1

łatwiejszy sposób jest zapewnienie prawidłowego fabrykę w konstruktorze testowym:

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

i dostarczenie kontekstu serwletu:

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

zobaczyć również peeskillet za odpowiedzi w tym wątku stackoverflow: [link]

(żaden z obecnie wymienionych rozwiązań pracował dla mnie)

0

wydaje taki problem istnieje od dawna. Jako wyjaśnienie @ lpiepiora potrzebujemy pojemnika testowego opartego na Servlet. I już jest jeden w jersey-test-framework-provider-grizzly2 (nie wiem, czy jest tam, gdy pytanie opublikowane), który jest GrizzlyWebTestContainerFactory, i wymaga innego DeploymentContext. Wyciągnij najnowszy git, a znajdziesz przykład w test-framework/providers/grizzly2/src/test/java/org/glassfish/jersey/test/grizzly/web/GrizzlyWebTest.java. Aby być proste i proste, wystarczy dodać te przesłonięcia w swojej klasie testowej bazy:

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

(. Wymienić YourResourceConfig z prawdziwego)

EDIT: Jeśli używasz Jersey z jersey-spring3 , powyższe rozwiązanie okaże się nieskuteczne z powodu braku wszystkich twoich fasoli Spring. Aby to naprawić:

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

Znaleziono równoważną odpowiedź [tutaj] (http://stackoverflow.com/a/29387230/185764). Niestety pojawił się nowy problem ...Oznacza to, że w przypadku użycia z jersey-spring3 (w celu integracji z Spring Framework), nie będzie zależności. Nadal próbuję znaleźć rozwiązanie. – fwonce