单元测试gwt-dispatch

min*_*ate 3 java gwt google-app-engine junit guice

我正在尝试使用JUnit为gwt-dispatch服务编写一些单元测试.使用我的调试器逐步完成测试时出现以下错误:

自定义提供程序出错,com.google.inject.OutOfScopeException:无法访问作用域对象.我们当前不在HTTP Servlet请求中,或者您可能忘记将com.google.inject.servlet.GuiceFilter应用为此请求的servlet过滤器.

我将在这里简化代码 - 希望我没有删除任何必要的东西.

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();
    }
}
}
Run Code Online (Sandbox Code Playgroud)

服务请求确实应该通过GuiceFilter,看起来没有设置过滤器.

有关注册过滤器需要做什么其他设置的任何想法?

Nam*_*ter 5

问题正是它所说的.您正在尝试访问范围对象,但您当前不在范围内.最有可能的是,您的测试是向注入器询问注入依赖关系树RequestScoped中具有RequestScoped对象的对象或对象,但测试没有做任何事情来进入范围.

绑定GuiceFilter在测试中并没有帮助,因为你的测试并不试图发送一个HttpServletRequest通过GuiceFilter一个servlet.

最好的选择是对代码进行单元测试.单独创建类,注入模拟.

假设您要进行某种集成测试,您有三种选择:

  1. 让您的测试安装一个调用的测试模块bindScope(RequestScoped.class, new FakeScope).该FakeScope班将实现Scope并有方法进入和退出的范围.您可能必须使用您依赖的对象的伪实现来"种子"范围.请参阅Guice CustomScopes wiki页面.这是集成测试的最佳选择,恕我直言
  2. 使用ServletScopes.scopeRequest(Javadoc)在模拟请求范围内运行部分测试代码.这有点难看,因为你需要传递一个Callable.
  3. 进行完整的端到端测试.启动服务器并使用Selenium发送请求.这种方式很难获得良好的覆盖率,因此我将其留给您真正需要浏览器测试的内容.

如果您正在测试的课程间接依赖于HttpServletRequest或者,那么事情可能会变得有点混乱HttpServletResponse.这些类可能难以正确设置.您的大多数类不应直接或间接依赖于servlet类.如果情况并非如此,那么您要么做错了,要么找到一个好的行动框架,让您的大部分代码都不依赖于这些类.

以下是方法1的示例,使用SimpleScopeGuice CustomScopes wiki页面:

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)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)