Модульное тестирование gwt-dispatch - PullRequest
3 голосов
/ 13 января 2011

Я пытаюсь написать несколько модульных тестов для службы gwt-dispatch с JUnit.При прохождении теста с отладчиком я получаю следующую ошибку:

Ошибка в настраиваемом поставщике, com.google.inject.OutOfScopeException: Невозможно получить доступ к объекту области.Либо мы в данный момент не находимся внутри запроса сервлета HTTP, либо вы, возможно, забыли применить com.google.inject.servlet.GuiceFilter в качестве фильтра сервлета для этого запроса.

Я собираюсь упроститькода здесь немного - надеюсь, я не убираю ничего необходимого.

import junit.framework.TestCase;
import net.customware.gwt.dispatch.client.standard.StandardDispatchService;

import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.ServletModule;
...

public class LoggedInServiceTest extends TestCase {

Injector i;
StandardDispatchService service;

protected com.google.inject.Injector getInjector() {
    return Guice.createInjector(new ServletModule(),
            new TestServletModule(),
            new ActionsHandlerModule(),
            new TestDispatchModule(),
            new OpenIdGuiceModule());

}

public void setUp() throws Exception {
    i = getInjector();
    service = i.getInstance(StandardDispatchService.class);
}

public void testNotLoggedIn() {
    try {
        GetProjectsResult result = (GetProjectsResult) service.execute(new GetProjectsAction());
        result.getSizeOfResult();
    } catch (Exception e) {
        fail();
    }
}
}

Сервисный запрос действительно должен проходить через GuiceFilter, и похоже, что этот фильтр не установлен.

Есть какие-нибудь идеи о том, какие еще настройки необходимо выполнить для регистрации фильтра?

Ответы [ 2 ]

5 голосов
/ 16 января 2011

Проблема только в том, что говорится.Вы пытаетесь получить доступ к объекту в области, но в данный момент вы не находитесь в области видимости.Скорее всего, ваш тест запрашивает у инжектора объект RequestScoped или объект, у которого есть RequestScoped объект в дереве зависимостей внедрения, но тест ничего не сделал для входа в область действия.

Привязка GuiceFilter в тесте не помогает, потому что ваш тест не пытается отправить сервлету HttpServletRequest через GuiceFilter.

Лучшим вариантом будет модульное тестирование вашего кода.,Создавайте свои классы изолированно, внедряя макеты.

Предполагая, что вы хотите провести какой-то интеграционный тест, у вас есть три варианта:

  1. Пусть ваш тест установит тестовый модуль, который называется bindScope(RequestScoped.class, new FakeScope).Класс FakeScope будет реализовывать Scope и иметь методы для входа и выхода из области.Возможно, вам придется «заполнить» область видимости поддельными реализациями объектов, от которых вы зависите.См. Вики-страницу Guice CustomScopes .Это лучший вариант для интеграционных тестов, IMHO
  2. Использование ServletScopes.scopeRequest ( Javadoc ) для запуска части тестового кода внутри области имитированного запроса.Это немного уродливо, так как вам нужно пройти Callable.
  3. Провести полный сквозной тест.Запустите свой сервер и отправьте ему запросы, используя Selenium.Очень сложно получить хорошее освещение таким образом, поэтому я бы оставил это для вещей, которые вам действительно нужен браузер для тестирования.

Все может стать немного запутанным, если класс, который вы тестируете, косвенно зависит отHttpServletRequest или HttpServletResponse.Эти классы могут быть сложными для правильной настройки.Большинство ваших классов не должны зависеть от классов сервлетов прямо или косвенно.Если это не так, вы либо делаете что-то не так, либо вам нужно найти хорошую платформу действий, которая позволит вам большей частью кода не зависеть от этих классов.

Вот пример подхода 1, использующегоSimpleScope из Guice Вики-страница CustomScopes :

public class LoggedInServiceTest extends TestCase {
  private final Provider<StandardDispatchService> serviceProvider;
  private final SimpleScope fakeRequestScope = new SimpleScope();
  private final HttpServletRequest request = new FakeHttpServletRequest();

  protected Injector createInjector() {
    return Guice.createInjector(new FakeRequestScopeModule(),
            new LoggedInServiceModule();
  }

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    Injector injector = createInjector();
    scope.enter();
    serviceProvider = injector.getProvider(StandardDispatchService.class);
  }

  @Override
  protected void tearDown() throws Exception {
    fakeRequestScope.exit()
    super.tearDown();
  }

  public void testNotLoggedIn() {
    fakeRequestScope.enter();
    // fill in values of request
    fakeRequestScope.seed(FakeHttpServletRequest.class, request);

    StandardDispatchService service = serviceProvider.get();
    GetProjectsAction action = new GetProjectsAction();
    try {
        service.execute(action);
        fail();
    } catch (NotLoggedInException expected) {
    }
  }

  private class FakeRequestScopeModule extends AbstractModule() {
    @Override
    protected void configure() {
      bind(RequestScoped.class, fakeRequestScope);
      bind(HttpServletRequest.class)
          .to(FakeHttpServletRequest.class)
          .in(RequestScoped.class)
    }
  }
}
0 голосов
/ 18 января 2011

Напишите интерфейс AppSession и две реализации: HttpAppSession и MockAppSession. Сделайте так, чтобы обработчики на стороне сервера зависели от AppSession, а не от HttpSession напрямую.

  • Используйте Guice для внедрения HttpSession в HttpAppSession. Это тот, который вы будете использовать в производстве и для запуска вашего приложения. в реальном контейнере сервлета.

  • MockAppSession не должен зависеть ни от HttpSession, ни от HttpServletRequest, ни от какой-либо другой области Guice Http. Это тот, который вы будете использовать во время тестирования.

Теперь ваш модуль Guice должен внедрить реализацию AppSession следующим образом:

bind(AppSession.class).to(MockAppSession.class)
bind(MockAppSession.class).in(Singleton.class)

Это разобьет тебя.

...