我有一些测试,如果某些Guice范围被错误地使用,我想失败.例如,@Singleton不应该有任何@RequestScoped或@TestScoped依赖关系(当然,Provider也可以).
在生产中,这部分解决了,因为在进入范围之前将构建热切的单例,导致OutOfScopeExceptions.但在发展中,单身人士将在范围内懒洋洋地创造,没有任何问题明显.
根据these two开放问题,似乎没有简单的内置方式来做到这一点.可以用SPI实现吗?我尝试使用一个TypeListener,但不清楚如何获得给定类型的依赖项.
解决方法
这不是一个微不足道的问题,但绝对是一个很好的问题!可能会有一个测试人员提到的范围约束问题.我想我可以让Junit跑步者用错误的绑定练习来产生警告.我稍后会更新这篇文章.
现在有一个如何获取绑定范围的示例.
模
public class ScopeTestModel extends ServletModule { @Override protected void configureServlets() { super .configureServlets(); bind(Key.get(Object.class,Names.named("REQ1"))).to(Object.class).in(ServletScopes.REQUEST); bind(Key.get(Object.class,Names.named("REQ2"))).to(RequestScopedObject.class); bind(Key.get(Object.class,Names.named("SINGLETON1"))).to(Object.class).asEagerSingleton(); bind(Key.get(Object.class,Names.named("SINGLETON2"))).to(Object.class).in(Scopes.SINGLETON); bind(Key.get(Object.class,Names.named("SINGLETON3"))).to(SingletonScopedObject.class); bind(Key.get(Object.class,Names.named("SESS1"))).to(Object.class).in(ServletScopes.SESSION); bind(Key.get(Object.class,Names.named("SESS2"))).to(SessionScopedObject.class); } }
测试用例
public class TestScopeBinding { private Injector injector = Guice.createInjector(new ScopeTestModel()); @Test public void testRequestScope() throws Exception { Binding<Object> req1 = injector.getBinding(Key.get(Object.class,Names.named("REQ1"))); Binding<Object> req2 = injector.getBinding(Key.get(Object.class,Names.named("REQ2"))); Scope scope1 = getScopeInstanceOrNull(req1); Scope scope2 = getScopeInstanceOrNull(req2); Assert.assertEquals(ServletScopes.REQUEST,scope1); Assert.assertEquals(ServletScopes.REQUEST,scope2); } @Test public void testSessionScope() throws Exception { injector.getAllBindings(); Binding<Object> sess1 = injector.getBinding(Key.get(Object.class,Names.named("SESS1"))); Binding<Object> sess2 = injector.getBinding(Key.get(Object.class,Names.named("SESS2"))); Scope scope1 = getScopeInstanceOrNull(sess1); Scope scope2 = getScopeInstanceOrNull(sess2); Assert.assertEquals(ServletScopes.SESSION,scope1); Assert.assertEquals(ServletScopes.SESSION,scope2); } @Test public void testSingletonScope() throws Exception { injector.getAllBindings(); Binding<Object> sng1 = injector.getBinding(Key.get(Object.class,Names.named("SINGLETON1"))); Binding<Object> sng2 = injector.getBinding(Key.get(Object.class,Names.named("SINGLETON2"))); Binding<Object> sng3 = injector.getBinding(Key.get(Object.class,Names.named("SINGLETON3"))); Scope scope1 = getScopeInstanceOrNull(sng1); Scope scope2 = getScopeInstanceOrNull(sng2); Scope scope3 = getScopeInstanceOrNull(sng3); Assert.assertEquals(Scopes.SINGLETON,scope1); Assert.assertEquals(Scopes.SINGLETON,scope2); Assert.assertEquals(Scopes.SINGLETON,scope3); } private Scope getScopeInstanceOrNull(final Binding<?> binding) { return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor<Scope>() { @Override public Scope visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) { throw new RuntimeException(String.format("I don't know how to handle the scopeAnnotation: %s",scopeAnnotation.getCanonicalName())); } @Override public Scope visitNoScoping() { if(binding instanceof LinkedKeyBinding) { Binding<?> childBinding = injector.getBinding(((LinkedKeyBinding)binding).getLinkedKey()); return getScopeInstanceOrNull(childBinding); } return null; } @Override public Scope visitEagerSingleton() { return Scopes.SINGLETON; } public Scope visitScope(Scope scope) { return scope; } }); } }
范围对象
@RequestScoped public class RequestScopedObject extends Object { } @SessionScoped public class SessionScopedObject extends Object { } @Singleton public class SingletonScopedObject extends Object { }