2011-10-05 23 views
1

我在單元測試框架中有一個接口:CDIMocker。我目前使用攔截器來允許在CDI容器中嘲笑。這是一個實驗 - 我正在考慮的一些單元測試方法之一。 (另一個主要的競爭者是在CDI之外的所有bean和單元測試中使用構造函數和方法注入 - 在這種情況下,這項工作變得更像CDI擴展中的學習練習)。CDI擴展:我可以在兩個範圍內公開一個接口嗎?

我有兩個自定義範圍 - TestClassScoped和TestMethodScoped。我的JUnit4自定義運行器將相應的Class和Method塊封裝在根據需要啓動和停止這些作用域的語句中。如果需要,它還會啓動Weld-SE的一個實例。它知道它是否在CDI中,因爲該分機記得。

模擬器接口與我們使用的任何地方相同。這將是很好的揭露它在兩個範圍內,所以我可以

// Sadly Static Injection currently doesn't work, but if it did 
@Inject @TestClassScoped 
private static CdiMocker s_classScopedMocker 

@Inject @TestMethodScoped 
private CdiMocker m_methodScopedMocker 

還有其他明顯的方法。我目前在CDI外部有一個工廠方法,可以返回這些實例(ThreadLocal),也可以創建一個新的短期活動實例。我也成功創建了兩個具體的類,並在其上聲明瞭不同的範圍。

我試過使用生產者方法註釋如上,但沒有運氣。也許是一個簡單的錯誤,也許是一個誤會。

@Produces @TestClassScoped 
public CdiMocker getClassScopedMockerForCdi() 
{ 
    return getTestClassContext().getMocker(); 
} 

@Produces @TestMethodScoped 
public CdiMocker getMethodScopedMockerForCdi() 
{ 
    return getTestMethodContext().getMocker(); 
} 

我從CDI文件有可能,因爲我已經做了聲明對注射點範圍的某些部分想,但我注意到,該實例<>接口不允許我選擇()使用範圍的註解所以也許這是錯誤的。

我可以提供兩個限定符。註釋是否可以同時用作限定符和範圍?

另一個想法是讓我的擴展提供兩個Bean <CdiMocker>,它們暴露相同的類但在不同的範圍內。他們還可以提供自定義create()和destroy(),因爲CdiMocker實例是由我的兩個自定義上下文管理的。我得到的CDI的印象是,一個給定的類只能存在於一個範圍內,那麼這是錯誤的嗎?

什麼是最好的任何建議?

感謝 - 理查德

(我喜歡開源的結果,但在上班時間做足夠我不得不問這樣不太可能的商業論證會公開審查我使用。一個攔截器現在有一個缺點,就是它必須留在原地,但是不知道我是否可以通過攔截擴展中的bean生命週期來實現某些功能,我們可以使用Alternatives來處理與我們的傳統應用服務器通信的通信層,但對於一些單元測試需要定製模擬和替代品太全球化。)

回答

1

我創建了

@Qualifier 
@Target({TYPE, METHOD, PARAMETER, FIELD}) 
@Retention(RUNTIME) 
@Documented 
public @interface Scoped 
{ 
    Class<? extends Annotation> value(); 
} 

我目前有兩個Bean實現。相關的(不尋常的)部分是:

/** 
* A Bean<> implementation for the CdiMocker beans 
*/ 
class MockerBean implements Bean<CdiMocker> 
{ 
    private final class ScopedAnnotation extends AnnotationLiteral<Scoped> implements Scoped 
    { 
     private static final long serialVersionUID = 1L; 
     public Class<? extends Annotation> value() { return m_context.getScope(); } 
    } 

    private final CdiMockContextControl m_context; 

    public MockerBean(CdiMockContextControl context) 
    { 
      m_context = context; 
    } 

bean類是CdiMocker。類

@Override 
    public Class<?> getBeanClass() 
    { 
      return CdiMocker.class; 
    } 

限定符包括我在上面定義的ScopedAnnotation。我還包括Default和Any。也許我需要刪除這些?

範圍由我的CdiMockContextControl接口返回。

​​

類型是我CdiMocker接口

@Override 
public Set<Type> getTypes() 
{ 
    Set<Type> types = new HashSet<Type>(); 
    types.add(CdiMocker.class); 
    types.add(Object.class); 
    return types; 
} 

因爲生命週期管理的其他地方我返回現有之一。

@Override 
public CdiMocker create(CreationalContext<CdiMocker> arg0) 
{ 
    return m_context.getMocker(); 
} 

...並且不要銷燬它。

@Override 
public void destroy(CdiMocker instance, CreationalContext<CdiMocker> ctx) 
{ 
    // It is managed by the Context, so I must not destroy it here. 
    ctx.release(); 
} 

解決方案是使用限定符,所以我想現在是「正確」。我認爲我可以用這種方式使用生命週期管理?

我的測試類(我的亞軍實例使用CDI)具有

/** 
* My CDI Extension makes a Mocking Context available in the Test Method Scope. 
* This will be created before every test method, then destroyed afterwards. 
*/ 
@Inject @Scoped(TestMethodScoped.class) 
private CdiMocker m_testMethodMocker; 
  • 理查德
相關問題