Существует решение этой проблемы, которое не требует пружины, при условии, что вы используете стандартный / стандартный поставщик инфраструктуры тестирования Grizzy2. Согласно этому ответу поставщик инфраструктуры jersey-test-framework-provider-grizzly2
не использует среду сервлета при создании контекста приложения. Ваши симптомы возникают из-за отсутствия ServletContext
экземпляра для инъекции.
Обходной путь - предоставить тестовый контейнер для модульных тестов самостоятельно. Сначала измените ваши зависимости:
<!--<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>
Затем измените ваш тест, указав контейнер сервлета 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();
}
};
}
Я предполагаю, что вы собираетесь использовать это в нескольких модульных тестах, поэтому может быть целесообразно расширить JerseyTest
, чтобы эта общая конфигурация могла выполняться автоматически. Кроме того, возможно, стоит просмотреть org.glassfish.jersey.test.grizzly.GrizzlyTestContainerFactory
, чтобы узнать, есть ли какие-либо функциональные возможности, предоставляемые тестовым контейнером, который вы хотите эмулировать / сохранить. Приведенный пример должен быть включен в ваш тест, чтобы хотя бы подтвердить, что это исправление.
РЕДАКТИРОВАТЬ: В моей собственной реализации мне потребовалась возможность по-прежнему предоставлять ResourceConfig
при генерации сервера. Я подозреваю, что это может быть обычным делом для других пользователей Jersey Test Framework. Ниже приводится рабочий пример предложенного TestContainerFactory
.
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);
}
}
К сожалению, GrizzlyWebContainerFactory
от Grizzly предоставит контекст сервлета, но не будет сконфигурирован с помощью конфигурации ресурса. И наоборот, GrizzlyHttpServerFactory
настроит приложение на ResourceConfig
, но не предоставит веб-контекст.
Мы можем обойти это, создав WebappContext
(extends ServletContext
) вручную, сконфигурировав его, а затем вставив его в конфигурацию ресурса с помощью AbstractBinder
.