Java 如何从Spock测试进行CDI/SE?

Java 如何从Spock测试进行CDI/SE?,java,groovy,junit,cdi,spock,Java,Groovy,Junit,Cdi,Spock,我一直在使用CDIUnit和其他各种形式的CDI/SE解决方案来实现测试(junit),这些测试可以减少模拟,并更多地使用我的应用程序堆栈(我想是集成测试) 无论如何,我也非常喜欢Spock进行测试,我认为应该抓紧时间从CDI/SE空间和Spock中混合一些东西,以便能够制定能够访问大部分CDI内容的规范 许多用于CDI的单元运行程序(CDIUnit、weldjunit、deltaspike、用于CDI或weld for SE的随机博客片段)都是JUnit运行程序,对于Spock来说似乎并不太适

我一直在使用CDIUnit和其他各种形式的CDI/SE解决方案来实现测试(junit),这些测试可以减少模拟,并更多地使用我的应用程序堆栈(我想是集成测试)

无论如何,我也非常喜欢Spock进行测试,我认为应该抓紧时间从CDI/SE空间和Spock中混合一些东西,以便能够制定能够访问大部分CDI内容的规范

许多用于CDI的单元运行程序(CDIUnit、weldjunit、deltaspike、用于CDI或weld for SE的随机博客片段)都是JUnit运行程序,对于Spock来说似乎并不太适合。经过多次修补,我提炼出了一个非常简单的东西:weld/se+spock和真正简单的@Inject。但它不起作用

似乎weld确实“启动”了,我的可注射体的后构造函数也启动了。但是,在Spock feature方法中,对可注入的引用为null。在进一步的测试中,我使用@InjectSetter而不是实例变量,setter似乎使用了非空引用,但在我的feature方法启动时;引用再次为空。我还把Weld和container@Shared弄得一团糟,并试图在setupSpec()生命周期方法中初始化;同样的结果

是否可以通过Spock测试进行简单的CDI操作?

下面是一个Spock的样本,展示了我试图实现的目标:

package fhw

import spock.lang.Specification
import javax.inject.Inject
import org.jboss.weld.environment.se.Weld
import org.jboss.weld.environment.se.WeldContainer
import spock.lang.Shared

public class Chompers
    extends Specification
{
    def Weld weld
    def WeldContainer container

    def setup()
    {
        println this
        weld = new Weld()
        container = weld.initialize()
        container.instance().select(this.class).get()
        //container.instance().select(this.class)
    }

    @Inject
    def SomethingToTest somethingToTest;

    //@Inject
    //def setSomethingToTest(SomethingToTest sst)
    //{
    //    somethingToTest = sst
    //    println "setter fired  and somethingToTest is null?  " + (null == somethingToTest)
    //}

    def "my first Test"()
    {
        given:
            println "given I used weld wrapper spec From spock (instance " + this + ")"


        when:
            println "when I do something, in this case, like just haveing @Inject annotation"

        then:
            somethingToTest
    }
}
更新 我有点“工作”。不确定原因或方式,甚至不确定它是否有任何好处(对于解决方案)。我想知道更多关于发生了什么以及为什么。样本:

package fhw

import org.junit.runner.RunWith
import spock.lang.*
import org.jboss.weld.environment.se.Weld
import org.jboss.weld.environment.se.WeldContainer
import javax.enterprise.inject.Instance

class WeldSpec
    extends Specification
{

    def Weld weld
    def WeldContainer container
    def me

    def setup()
    {
        weld = new Weld()
        container = weld.initialize()
        me = container.instance().select(this.class).get()
    }

    def cleanup()
    {
        if(weld)
        {
            weld.shutdown()
        }
    }
}



更新2 因此,我观察/推测,真正发生的事情是斯波克创建了我的规范的一个实例(“this”),然后在使用weld/se的设置中,我使用select().get()调用(“me”)创建了另一个实例。简单的打印显示“我”!='这“实际上是通过select().get()创建的托管实例上发生的注入。我想大概是这样

所以我想我真正想要的是在“这个”上注射。通过谷歌搜索,我偶然发现:这是一个类似的东西。我受到DeltaSpike的injectFields和重构WeldSpec的启发,比如:

package fhw

import spock.lang.*
import javax.enterprise.inject.spi.BeanManager
import javax.enterprise.inject.spi.InjectionTarget
import org.jboss.weld.environment.se.Weld
import org.jboss.weld.environment.se.WeldContainer
import javax.enterprise.context.spi.CreationalContext
import javax.enterprise.inject.spi.AnnotatedType

class WeldSpec
    extends Specification
{
    def Weld weld
    def WeldContainer container

    def setup()
    {
        weld = new Weld()
        container = weld.initialize()
        BeanManager beanManager = container.getBeanManager()
        CreationalContext<? extends WeldSpec> creationalContext = beanManager.createCreationalContext(null)
        AnnotatedType<? extends WeldSpec> annotatedType = beanManager.createAnnotatedType((Class<? extends WeldSpec>) this.getClass())
        InjectionTarget<? extends WeldSpec> injectionTarget = beanManager.createInjectionTarget(annotatedType)
        injectionTarget.inject(this, creationalContext);            
    }

    def cleanup()
    {
        if(weld)
        {
            weld.shutdown()
        }
    }
}


现在看看这是否有什么好处……

根据更新2;我有些东西在工作

Update2有一个性能问题:由于setup()在每个特征方法之前运行,每个特征方法都会初始化Weld,并扫描类路径和所有

我将它移到了static,但在这种情况下没有关机(我在关机挂钩之外找不到一个地方放置它,但可能它甚至不需要用于测试):

类CDisspecification扩展了规范{
专用静态焊缝
专用静态焊接容器
专用静态BeanManager BeanManager
静止的{
焊缝=新焊缝()
容器=焊接。初始化()
beanManager=container.getBeanManager()
}
def设置(){

creationalcontext看看这个问题,它可能会有帮助:有趣——昨晚看到了那篇帖子,但没有仔细检查,因为这起案件涉及阿奎利安。海报的工作还可以,但不确定它是否会帮助我。它确实添加了另一个数据点;我不是唯一一个看到这一点的人。我已经探索过(目前正在探索)使用spock扩展并点击visitSpecAnnotation()等生命周期方法,看看CDI/Weld/SE在那里是否能更好地工作。也许我应该看看visitFeatureAnnotation()太好了。你使用的是什么版本的weld?主要问题是注入到你的spock案例中是不起作用的,但是如果你至少在2.x上,那么现在有一些选项可以选择“org.spockframework:spock core:1.0-groovy-2.4”和“org.jboss.weld.se:weld se-se core:2.2.10.Final”。我很想知道更多关于这些选项的信息;我真的很想得到这个to工作…Spock扩展(使用AbstractAnnotationDrivenExtension)几乎可以让我在同一个地点启动一个容器,但是斯波克在调用特征方法之前擦除了注射。谢谢你的反馈。我没有考虑在每个特征方法之前制作CDI容器的性能。但是,我觉得从每个特征方法开始使用一个新容器是很重要的。也许斯波克的setupSpec()和cleanupSpec()可以摆脱静态块,在fixture关闭时提供一个钩子?
package fhw;

import javax.annotation.PostConstruct;
import javax.inject.Named;


@Named
public class SomethingToTest
{
    public SomethingToTest() {}

    @PostConstruct
    private void init()
    {
        System.out.println("SomethingToTest:  post construction");
    }


    public String upShift(String in)
    {
        String s = null;
        if(null != in)
        {
            s = in.toUpperCase();
        }
        return(s);
    }

}
package fhw

import spock.lang.*
import javax.enterprise.inject.spi.BeanManager
import javax.enterprise.inject.spi.InjectionTarget
import org.jboss.weld.environment.se.Weld
import org.jboss.weld.environment.se.WeldContainer
import javax.enterprise.context.spi.CreationalContext
import javax.enterprise.inject.spi.AnnotatedType

class WeldSpec
    extends Specification
{
    def Weld weld
    def WeldContainer container

    def setup()
    {
        weld = new Weld()
        container = weld.initialize()
        BeanManager beanManager = container.getBeanManager()
        CreationalContext<? extends WeldSpec> creationalContext = beanManager.createCreationalContext(null)
        AnnotatedType<? extends WeldSpec> annotatedType = beanManager.createAnnotatedType((Class<? extends WeldSpec>) this.getClass())
        InjectionTarget<? extends WeldSpec> injectionTarget = beanManager.createInjectionTarget(annotatedType)
        injectionTarget.inject(this, creationalContext);            
    }

    def cleanup()
    {
        if(weld)
        {
            weld.shutdown()
        }
    }
}
package fhw

import spock.lang.*
import javax.inject.Inject
import fhw.spock.*

public class Bonnie
    extends WeldSpec
{
    @Inject 
    def SomethingToTest somethingToTest;

    def "my silly first cdi-spock test"()
    {        
        when:
            def s = somethingToTest.upShift("fred")

        then:
            "FRED" == s
    }
}