2011-10-05 71 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; 
  • 理查德
相关问题