Java – how to verify the use of Guice scope in testing?
I have some tests. If some Guice ranges are used incorrectly, I want to fail For example, @ singleton should not have any @ requestscoped or @ testscoped dependencies (of course, providers can also)
In production, this is partially resolved because eager singletons will be built before entering the scope, resulting in outofscopeexceptions But in the process of development, single people will create lazily within the scope, without any obvious problems
According to these two open questions, there seems to be no simple built-in way to do this Can it be implemented with SPI? I try to use a typelistener, but I don't know how to get dependencies of a given type
Solution
This is not a trivial problem, but it is definitely a good problem! There may be a scope constraint problem mentioned by the tester I think I can get JUnit runners to generate warnings with wrong binding exercises I will update this article later
Now there is an example of how to get the binding scope
model
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); } }
test case
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; } }); } }
Scope object
@RequestScoped public class RequestScopedObject extends Object { } @SessionScoped public class SessionScopedObject extends Object { } @Singleton public class SingletonScopedObject extends Object { }