2013-08-27 48 views
10

我有一些測試,如果某些Guice示波器使用不當,我想失敗。例如,@Singleton不應具有任何@RequestScoped@TestScoped依賴性(當然,Provider<>也沒關係)。如何驗證Guice示波器在測試中的使用情況?

在生產中,部分解決了這個問題,因爲在輸入範圍之前將構造急切的單身人士,導致OutOfScopeException s。但是在開發過程中,單身人士會在範圍內懶散地創造出來,而且沒有問題。

通過thesetwo來判斷未解決的問題,似乎沒有簡單的內置方法來執行此操作。我可以使用SPI來實現嗎?我嘗試使用TypeListener,但不清楚如何獲得給定類型的依賴關係。

回答

1

以下是我已經ACCOM使用Guice的4.0 beta版本,使用ProvisionListener。我試過TypeListener,但似乎在Guice必須綁定該類型的依賴關係之前調用了TypeListener。這導致了異常,甚至在一種情況下導致了死鎖。

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

這不是一個小問題,但絕對是一個很好的問題!可能會有一位測試人員提到您提到的作用域綁定問題。我想我可以讓一個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); 
    } 
} 

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

範圍內的對象

@RequestScoped 
public class RequestScopedObject extends Object { 

} 

@SessionScoped 
public class SessionScopedObject extends Object { 

} 

@Singleton 
public class SingletonScopedObject extends Object { 

} 
+1

謝謝,這當然是一個難題。爲了測試綁定是否是單例,還有'Scopes.isSingleton()'。難題的另一部分是我被卡住的地方。我已經找到了即將發佈的Guice 4解決方案,但如果可能的話,我仍然會喜歡Guice 3解決方案。 –

相關問題