单元测试 gwt-dispatch
我正在尝试使用 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();
}
}
}
服务请求确实应该通过 GuiceFilter,但看起来该过滤器尚未设置。
关于注册过滤器需要进行哪些其他设置有什么想法吗?
I'm trying to write some unit tests for a gwt-dispatch service with JUnit. I'm getting the following error when stepping through the test with my debugger:
Error in custom provider, com.google.inject.OutOfScopeException: Cannot access scoped object. Either we are not currently inside an HTTP Servlet request, or you may have forgotten to apply com.google.inject.servlet.GuiceFilter as a servlet filter for this request.
I'm going to simplify the code a bit here -- hopefully I'm not stripping out anything necessary.
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();
}
}
}
The service request is indeed supposed to be going through a GuiceFilter, and it looks like that filter is not being set.
Any ideas on what other setup needs to be done to register the filter?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
问题正是它所指出的。您正在尝试访问有作用域的对象,但您当前不在该作用域内。最有可能的是,您的测试向注入器询问
RequestScoped
对象或在注入依赖树中具有RequestScoped
对象的对象,但测试没有执行任何操作进入范围。在测试中绑定
GuiceFilter
没有帮助,因为您的测试并没有尝试通过GuiceFilter
将HttpServletRequest
发送到 servlet。最好的选择是对代码进行单元测试。隔离地创建类,注入模拟。
假设您想要进行某种集成测试,您有三个选择:
bindScope(RequestScoped.class, new FakeScope)
的测试模块。FakeScope
类将实现Scope
并具有进入和退出范围的方法。您可能必须使用您所依赖的对象的虚假实现来“播种”范围。请参阅 Guice CustomScopes wiki 页面。这是集成测试的最佳选择,恕我直言,ServletScopes.scopeRequest
(Javadoc) 在模拟请求范围内运行部分测试代码。这有点难看,因为您需要传递一个 Callable。如果您正在测试的类间接依赖于
HttpServletRequest
或HttpServletResponse
,事情可能会变得有点混乱。正确设置这些类可能具有挑战性。大多数类不应直接或间接依赖于 servlet 类。如果情况并非如此,那么您要么做错了什么,要么需要找到一个好的操作框架,让您的大部分代码不依赖于这些类。以下是方法 1 的示例,使用 Guice 中的
SimpleScope
CustomScopes 维基页面:The problem is just what it states. You are trying to access a scoped object, but you are not currently in the scope. Most likely, your test is asking the injector for a
RequestScoped
object or an object that has aRequestScoped
object in the injection dependency tree, but the test didn't do anything to enter the scope.Binding the
GuiceFilter
in the test doesn't help, because your test isn't trying to send anHttpServletRequest
throughGuiceFilter
to a servlet.The best option would be to unit test your code. Create your classes in isolation, injecting mocks.
Assuming you want to do some kind of integration test, you have three options:
bindScope(RequestScoped.class, new FakeScope)
. TheFakeScope
class would implementScope
and have methods to enter and exit the scope. You may have to "seed" the scope with fake implementations of objects you depend on. See the Guice CustomScopes wiki page. This is the best option for integration tests, IMHOServletScopes.scopeRequest
(Javadoc) to run part of the test code inside of a simulated request scope. This gets a bit ugly since you need to pass aCallable
.Things might get a bit messy if the class you are testing depends indirectly on
HttpServletRequest
orHttpServletResponse
. These classes can be challenging to setup correctly. Most of your classes should not depend on the servlet classes directly or indirectly. If that is not the case, you are either doing something wrong or you need to find a good action framework that allows you have most of your code not depend on these classes.Here's an example of approach 1, using
SimpleScope
from the Guice CustomScopes wiki page:编写一个AppSession接口和两个实现:HttpAppSession和MockAppSession。
让您的服务器端处理程序依赖于 AppSession 而不是直接依赖于 HttpSession。
使用 Guice 将 HttpSession 注入 HttpAppSession。这是您将在生产中使用并实际运行您的应用程序的那个。在真实的 servlet 容器中。
MockAppSession 不应依赖于 HttpSession、HttpServletRequest 或任何其他 Guice Http 范围。这就是您将在测试期间使用的那个。
现在,您的 Guice 模块应该注入一个 AppSession 实现,如下所示:
这将为您解决问题。
Write an AppSession interface and two implementations: HttpAppSession and MockAppSession.
Make your server-side handlers depend on AppSession and not on HttpSession directly.
Use Guice to inject HttpSession into HttpAppSession. That's the one you'll use in production, and for actually running your app. within a real servlet container.
The MockAppSession should not depend on HttpSession, nor HttpServletRequest, nor any other Guice Http scope. That's the one you'll use during testing.
Now, your Guice module should inject an AppSession implementation as follows:
That'll sort you out.