wake-up-neo.com

Probleme beim Ausführen von JerseyTest beim Umgang mit HttpServletResponse

Hier ist ein Beispiel für eine Ressourcenklasse:

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

Und der JerseyTest für die Ressource:

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

Ich kann Trikottests für alle anderen Ressourcen ausführen, mit Ausnahme derer, die @Context HttpServletRequest als Eingabeparameter verwenden. Es gibt einen InternalServerErrorException: HTTP 500 Internal Server Error.

Es folgt der 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) 
16
user2638465

Ihre Ausnahme hängt mit der Tatsache zusammen, dass die HttpServletRequestnull ist.

Jersey Dokumentation sagt:

3.6. Verwendung von @Context

In früheren Abschnitten wurde die Verwendung von @Context eingeführt. In Kapitel 5 der JAX-RS-Spezifikation sind alle Standard-JAX-RS-Java-Typen aufgeführt, die mit @Context verwendet werden können.

Wenn Sie eine JAX-RS -Anwendung mit servletthen ServletConfig implementieren, stehen ServletContext, HttpServletRequest und HttpServletResponse mit @Context zur Verfügung.

Ich vermute, dass Sie jersey-test-framework-provider-grizzly2 verwenden, der es nicht unterstützt.

Wenn Sie Zugriff auf HttpServletResponse haben möchten, entfernen Sie diese Abhängigkeit und fügen Sie Folgendes hinzu:

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

Jetzt möchten Sie JerseyTest eigentlich anweisen, den richtigen Testserver zu starten. Dazu müssen Sie eine Methode protected TestContainerFactory getTestContainerFactory() überschreiben. Bitte achten Sie darauf, <your-Java-package> durch den tatsächlichen Namen Ihres Pakets zu ersetzen .

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

        }
    };
}

Sie können auch org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory für eine bessere Implementierung der Fabrik überprüfen.

21
lpiepiora

Sie können auch ein verspottetes HttpServletRequest-Objekt in die configure-Methode einfügen. Hier ist ein Beispiel für 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<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);
                            }
                        });
12
Alexey Gavrilov

Also endlich bekomme ich eine funktionierende Lösung (Es kommt der populärsten Antwort nahe, aber mit kleinen Änderungen):


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>

Fügen Sie der Anwendung die folgende abstrakte Klasse hinzu:

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

                    }
                };
            }
        };
    }

}

Und um Rest zu testen, musst du folgendes tun:

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

Siehe auch peeskillets Antworten auf diesen Stapelüberlauf-Thread:[link]

(Keine der derzeit aufgelisteten Lösungen hat für mich funktioniert)

0
NS du Toit

Dieses Problem scheint schon lange da zu sein. Zur Erklärung von @ lpiepiora benötigen wir einen Servlet-basierten Testcontainer. Und es gibt bereits eine in jersey-test-framework-provider-grizzly2 (weiß nicht, ob es diese gibt, wenn die Frage gepostet wird), die GrizzlyWebTestContainerFactory ist und eine andere DeploymentContext erfordert. Ziehen Sie den neuesten Git und Sie finden ein Beispiel in test-framework/providers/grizzly2/src/test/Java/org/glassfish/jersey/test/grizzly/web/GrizzlyWebTest.Java . Um klar und einfach zu sein, müssen Sie in Ihrer Basistestklasse nur die folgenden Überschreibungen hinzufügen:

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

(Ersetzen Sie YourResourceConfig durch Ihre echte.)

BEARBEITEN: Wenn Sie Jersey mit jersey-spring3 verwenden, schlägt die oben beschriebene Lösung fehl, da all Ihre Spring Beans fehlen. Etwas reparieren:

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