Сбой внедрения контекста сервлета при использовании тестовой среды джерси - PullRequest
8 голосов
/ 02 декабря 2010

Я начинаю с джерси и пытаюсь заставить работать с ним freemarker, используя TDD.Я хочу сделать ViewProcessor для своих шаблонов, но не могу вставить контекст сервлета в класс.

Вот код класса:

@Provider
public class myProcessor implements ViewProcessor<Template> {

    [...]

    @Context
    public ServletContext myContext;

    [...]

 freemarkerConfiguration.setTemplateLoader(
       new WebappTemplateLoader(myContext,
           myContext.getInitParameter("freemarker.template.path")));

    [...]
    }

А вот тестовый код:

public class myProcessorTest extends JerseyTest {

    public static myProcessor mp;

    public myProcessorTest() throws Exception{
        super(new WebAppDescriptor.Builder("com.domain").build());
    }

    @Test
    public void firstTest(){
        mp = new myProcessor();
        String path = new String("test.ftl");
        Template template = mp.resolve(path);
        assertNotNull(template);
    }
}

Я использую maven с зависимостями следующим образом:

<dependency>
    <groupId>com.sun.jersey.jersey-test-framework</groupId>
    <artifactId>jersey-test-framework-grizzly</artifactId>
    <version>1.5-SNAPSHOT</version>
    <scope>test</scope>
</dependency>

Мой код работает нормально при развертывании на локальном сервере Jetty.Но если я хочу проверить код в моей IDE, он не смог ввести контекст сервлета (@Context): myContext равен null при запуске теста: /

Я думаю, что ячто-то упустил, но я полный новичок в мире сервлетов.

Ответы [ 2 ]

0 голосов
/ 03 февраля 2017

Существует решение этой проблемы, которое не требует пружины, при условии, что вы используете стандартный / стандартный поставщик инфраструктуры тестирования 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.

0 голосов
/ 12 февраля 2014

Есть несколько способов сделать это.Удалите конструктор и реализуйте метод configure () следующим образом:

public class myProcessorTest extends JerseyTest {

    public static myProcessor mp;

    @Override
    protected AppDescriptor configure() {
    return new WebAppDescriptor.Builder("com.domain")
        .contextParam("contextConfigLocation", "classpath:/applicationContext.xml")
        .contextPath("/").servletClass(SpringServlet.class)
        .contextListenerClass(ContextLoaderListener.class)
        .requestListenerClass(RequestContextListener.class)
        .build();
  }

или, альтернативно, вы можете аннотировать свой тест с помощью контекста Spring:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class MyProcessorTest extends JerseyTest {

  public static myProcessor mp;
...