Hay una solución a este problema que no requiere primavera, suponiendo que está utilizando el proveedor de marco de prueba Grizzy2 predeterminado/estándar. De acuerdo con this answer, el proveedor del framework jersey-test-framework-provider-grizzly2
no utiliza un entorno de servlet al construir el contexto de la aplicación. Sus síntomas son el resultado de no haber ServletContext
instancia para inyectar.
La solución consiste en proporcionar usted mismo el contenedor de prueba para la unidad. En primer lugar, modificar sus dependencias:
<!--<dependency>
<groupId>org.glassfish.jersey.test-framework.providers</groupId>
<artifactId>jersey-test-framework-provider-grizzly2</artifactId>
<version>2.25</version>
<scope>test</scope>
</dependency>-->
<dependency>
<groupId>org.glassfish.jersey.test-framework</groupId>
<artifactId>jersey-test-framework-core</artifactId>
<version>2.25</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-grizzly2-servlet</artifactId>
<version>2.25</version>
</dependency>
A continuación, modifique su ensayo para proporcionar un contenedor de servlets Grizzy:
@Override
protected TestContainerFactory getTestContainerFactory() throws TestContainerException {
return (final URI baseUri, final DeploymentContext deploymentContext) ->
new TestContainer() {
private HttpServer server = null;
@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-package-name>"));
} catch (final ProcessingException | IOException cause) {
throw new TestContainerException(cause);
}
}
@Override
public void stop() {
this.server.shutdownNow();
}
};
}
supongo que se va a utilizar esto en múltiples pruebas de unidad, lo que puede ser sabio extender JerseyTest
así que esta configuración común se puede realizar automáticamente. Además, puede valer la pena revisar org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory
para ver si hay alguna funcionalidad proporcionada por el contenedor de prueba que desea emular/preservar. El ejemplo proporcionado debería poder soltarse en su prueba para, al menos, confirmar que se trata de una solución.
EDIT: En mi propia implementación, necesitaba la capacidad de seguir suministrando un ResourceConfig
al generar el servidor. Sospecho que este es el caso común para otros usuarios de Jersey Test Framework. A continuación se muestra un ejemplo de trabajo del TestContainerFactory
propuesto.
import java.io.IOException;
import java.net.URI;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.ws.rs.ProcessingException;
import javax.ws.rs.core.UriBuilder;
import org.glassfish.grizzly.http.server.HttpServer;
import org.glassfish.grizzly.servlet.WebappContext;
import org.glassfish.hk2.utilities.binding.AbstractBinder;
import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
import org.glassfish.jersey.test.DeploymentContext;
import org.glassfish.jersey.test.spi.TestContainer;
import org.glassfish.jersey.test.spi.TestContainerException;
import org.glassfish.jersey.test.spi.TestContainerFactory;
import org.glassfish.jersey.test.spi.TestHelper;
public class RestTestContainerFactory implements TestContainerFactory {
public static class RestTestContainer implements TestContainer {
private static final Logger LOGGER = Logger.getLogger(RestTestContainer.class.getName());
private URI baseUri = null;
private final HttpServer server;
public RestTestContainer(final URI baseUri, final DeploymentContext context) {
this.baseUri = UriBuilder.fromUri(baseUri).path(context.getContextPath()).build();
if(LOGGER.isLoggable(Level.INFO)) {
LOGGER.info("Creating RestRestContainer configured at the base URI "+TestHelper.zeroPortToAvailablePort(baseUri));
}
try {
final WebappContext webContext = new WebappContext("TestContext", context.getContextPath());
context.getResourceConfig()
.register(new AbstractBinder() {
@Override
protected void configure() {
bind(webContext).to(ServletContext.class);
}
});
this.server = GrizzlyHttpServerFactory.createHttpServer(this.baseUri, context.getResourceConfig(), false);
webContext.deploy(this.server);
} catch (final ProcessingException cause) {
throw new TestContainerException(cause);
}
}
@Override
public ClientConfig getClientConfig() {
return null;
}
@Override
public URI getBaseUri() {
return baseUri;
}
@Override
public void start() {
if(server.isStarted()) {
LOGGER.warning("Ignoring start request - RestTestContainer is already started");
} else {
LOGGER.fine("Starting RestTestContainer...");
try {
server.start();
if(baseUri.getPort() == 0) {
baseUri = UriBuilder.fromUri(baseUri)
.port(server.getListener("grizzly").getPort())
.build();
LOGGER.info("Started GrizzlyTestContainer at the base URI "+baseUri);
}
}
catch(final ProcessingException | IOException cause) {
throw new TestContainerException(cause);
}
}
}
@Override
public void stop() {
if(server.isStarted()) {
LOGGER.fine("Stopping RestTestContainer...");
server.shutdownNow();
} else {
LOGGER.warning("Ignoring stop request - RestTestContainer is already stopped");
}
}
}
@Override
public TestContainer create(final URI baseUri, final DeploymentContext context) {
return new RestTestContainer(baseUri,context);
}
}
frustrante, grisáceo de GrizzlyWebContainerFactory
proporcionará un contexto servlet, pero no configurar con una configuración de recursos. Inversamente, GrizzlyHttpServerFactory
configurará una aplicación con un ResourceConfig
, pero no proporcionará un contexto web.
podemos trabajar en torno a este mediante la creación de la WebappContext
(se extiende ServletContext
) manualmente, configurar, y luego inyectarla en la configuración de recursos por medio de un AbstractBinder
.