2013-08-27 7 views
10

Mam kilka testów, które chciałbym zawieść, jeśli niektóre zakresy Guice są używane niepoprawnie. Na przykład model @Singleton nie powinien mieć żadnych zależności (lub @TestScoped).Jak mogę sprawdzić użycie zakresu Guice w testach?

W produkcji jest to częściowo rozwiązane, ponieważ singletony z niecierpliwością będą budowane przed wprowadzeniem zakresu, co daje w wyniku OutOfScopeException s. Ale w fazie rozwoju singleton zostanie utworzony leniwie, gdy znajdzie się w zasięgu i nie będzie żadnych problemów.

Sądząc po thesetwo otwartych kwestii, wydaje się, że nie ma łatwego, wbudowanego sposobu, aby to zrobić. Czy mogę to osiągnąć za pomocą SPI? Próbowałem użyć TypeListener, ale nie jest jasne, jak uzyskać zależności danego typu.

Odpowiedz

1

Oto jak mam towa wyliczyłem to z wersją 4.0 beta Guice, używając ProvisionListener. Próbowałem TypeListener, ale wygląda na to, że TypeListener są wywoływane, zanim Guice z konieczności ma powiązania dla zależności tego typu. Powodowało to wyjątki, a nawet zakleszczenie w jednym przypadku.

private static class ScopeValidator implements ProvisionListener { 
    private @Inject Injector injector; 
    private @Inject WhateverScope scope; 

    @Override 
    public <T> void onProvision(ProvisionInvocation<T> provision) { 
     if (injector == null) { 
      // The injector isn't created yet, just return. This isn't a 
      // problem because any scope violations will be caught by 
      // WhateverScope itself here (throwing an OutOfScopeException) 
      return; 
     } 

     Binding<?> binding = provision.getBinding(); 
     Key<?> key = binding.getKey(); 

     if (Scopes.isSingleton(binding) && binding instanceof HasDependencies) { 
      Set<Dependency<?>> dependencies = ((HasDependencies) binding).getDependencies(); 

      for (Dependency<?> dependency : dependencies) { 
       Key<?> dependencyKey = dependency.getKey(); 
       Binding<?> dependencyBinding = injector.getExistingBinding(dependencyKey); 

       if (dependencyBinding != null && Scopes.isScoped(dependencyBinding, whateverScope, WhateverScoped.class)) { 
        throw new ProvisionException(String.format(
          "Singleton %s depends on @WhateverScoped %s", 
          key, dependencyKey)); 
       } 
      } 
     } 
    } 
} 
2

to nie jest trywialny problem, ale zdecydowanie jest to dobre pytanie! Może istnieć tester problemów z wiązaniem zakresu, o którym wspomniałeś. Myślę, że mógłbym zrobić biegacza Junit, by wygenerować ostrzeżenie z niewłaściwą praktyką wiążącą. Zaktualizuję ten post później.

Na razie istnieje przykład, jak uzyskać zakresy wiązania.

Moduł

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); 
    } 
} 

TestCase

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; 
     } 
    }); 
    } 
} 

lunetą obiektów

@RequestScoped 
public class RequestScopedObject extends Object { 

} 

@SessionScoped 
public class SessionScopedObject extends Object { 

} 

@Singleton 
public class SingletonScopedObject extends Object { 

} 
+1

Dzięki, to z pewnością element układanki. Do testowania, czy wiązanie jest pojedynczym, czy nie, istnieje również 'Scopes.isSingleton()'. Druga część układanki to miejsce, w którym utknąłem. Znalazłem rozwiązanie Guice 4, które mam zamiar opublikować, ale nadal wolałbym, jeśli to możliwe, rozwiązanie Guice 3. –

Powiązane problemy