CDI 扩展:我可以在两个作用域中公开一个接口吗?
我在单元测试框架中有一个接口:CDIMocker。我目前正在使用拦截器来允许在 CDI 容器中进行模拟。这是一个实验——我正在考虑的几种单元测试方法之一。 (另一个主要竞争者是对 CDI 之外的所有 bean 和单元测试使用构造函数和方法注入 - 在这种情况下,这项工作更像是 CDI 扩展中的学习练习)。
我有两个自定义范围 - TestClassScoped 和 TestMethodScoped。我的 JUnit4 自定义运行程序将适当的类和方法块包装在根据需要启动和停止这些作用域的语句中。如果需要,它还会启动 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 文档的某些部分可以像我所做的那样在注入点上声明范围,但我注意到 Instance<>接口不允许我使用范围注释来 select() 所以这可能是错误的。
我可以提供两个限定符。注释可以同时是限定符和范围吗?
另一个想法是让我的扩展提供两个 Bean
关于什么是最好的有什么建议吗?
谢谢 - Richard
(我很想开源结果,但在工作时间里已经做了足够多的工作,所以我不得不问,所以不太可能。商业争论将是公开审查。我现在使用拦截器,缺点是它必须留在原处,但想知道我是否可以通过拦截扩展中的 bean 生命周期来实现某些目标。我们可以使用替代方案来实现与旧应用程序服务器通信的通信层等功能,但对于某些功能,单个单元测试需要自定义。模拟和替代品太全球化了。)
I have an interface in a unit testing framework: CDIMocker. I'm currently using an interceptor to allow mocking in a CDI container. It's an experiment - one of a couple of approaches to unit testing I'm considering. (The other main contender is to use constructor and method injection for all beans and unit test outside CDI - in which case this work becomes more a learning exercise in CDI Extensions).
I have two custom scopes - TestClassScoped and TestMethodScoped. My JUnit4 custom runner wraps the appropriate Class and Method blocks in statements that start and stop these scopes as needed. It also starts an instance of Weld-SE if needed. It knows if it's in CDI because the Extension remembers.
The mocker interface is the same wherever it us used. It would be nice to expose it in both scopes, so I could
// Sadly Static Injection currently doesn't work, but if it did
@Inject @TestClassScoped
private static CdiMocker s_classScopedMocker
@Inject @TestMethodScoped
private CdiMocker m_methodScopedMocker
There are other obvious ways. I currently have a factory method on a singleton outside CDI that can return either of these instances (ThreadLocal), or create a new short lived one. I have also had success creating two concrete classes and declaring different scopes on them.
I've tried using Producer Methods annotated as above, but no luck. Perhaps a simple mistake, perhaps a misunderstanding.
@Produces @TestClassScoped
public CdiMocker getClassScopedMockerForCdi()
{
return getTestClassContext().getMocker();
}
@Produces @TestMethodScoped
public CdiMocker getMethodScopedMockerForCdi()
{
return getTestMethodContext().getMocker();
}
I thought from some part of the CDI documentation it was possible to declare scopes on injection points as I have done, but I note that the Instance<> interface does not allow me to select() using scoped annotation so maybe that is wrong.
I could provide two qualifiers. Can an annotation be a Qualifier and a Scope at the same time?
Another idea would be to have my extension provide two Bean<CdiMocker>, both exposing the same class but in different scopes. They could also provide custom create() and destroy() because the CdiMocker instances are managed by my two custom Contexts. The impression I get of CDI is that a given Class can only live in one Scope, so would this be Wrong?
Any suggestions on what is best?
Thanks
- Richard
(I'd love to open source the result, but have done enough in work time I'd have to ask so not likely. The business argument would be public review. I use an Interceptor now with the disadvantage that it has to be left in place, but wonder if I could achieve something by intercepting the bean lifecycle in the extension. We can use Alternatives for things like the comms layer that talks to our legacy app server, but for some things a single unit test wants a custom mock and Alternatives are too global.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我已经创建了
当前有两个 Bean 实现。相关(不寻常)部分是:
bean 类是 CdiMocker.class
限定符包括我上面定义的 ScopedAnnotation。我还包括了“默认”和“任意”。也许我需要删除这些?
范围由我的 CdiMockContextControl 接口返回。
类型是我的 CdiMocker 接口,
因为生命周期是在其他地方管理的,所以我返回现有的接口。
...并且不要破坏它。
解决方案是使用限定符,所以我认为它现在是“正确的”。我想我可以通过这种方式使用生命周期管理吗?
我的测试类(我的 Runner 使用 CDI 实例化)有
I've created
I currently have two Bean implementations. Relevant (unusual) parts are:
The bean class is CdiMocker.class
The Qualifiers include my ScopedAnnotation defined above. I've also included Default and Any. Maybe I need to remove these?
The scope is returned by my CdiMockContextControl interface.
Type is my CdiMocker interface
Because the lifecycle is managed elsewhere I return the existing one.
... and don't destroy it.
The solution is using Qualifiers, so I suppose it is now "Correct". I assume I can use lifecycle management in this way?
My test class (which my Runner instantiates using CDI) has