如何从Spock Test做CDI / SE?

时间:2015-04-20 13:51:59

标签: java groovy junit cdi spock

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

无论如何,我也非常喜欢Spock进行测试,并且认为它应该是从CDI / SE空间混搭的东西,并且能够制作能够访问大部分CDI内容的规格。

CDI的许多单位参赛者(CDIUnit,weldjunit,deltaspike,随机博客片段做cdi或焊接SE) - 都是JUnit Runners,并且看起来并不适合Spock。经过多次修补后,我已经提炼成一个非常简单的东西:焊接/ se + spock,非常简单的@Inject。但它不起作用。

似乎焊接确实'开始'并且我的注射器的后置构造器触发了。但是,Spock特征方法中对injectable的引用为null。在进一步的测试中,我做了一个@Inject setter而不是实例变量,并且setter确实似乎用非null引用触发,但是当我的feature方法触发时;引用再次为null。我也搞砸了焊接和容器@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()
        }
    }
}

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 = me.somethingToTest.upShift("fred")

        then:
            "FRED" == s 
    }
}

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

}

更新2

所以我观察/推测真正发生的事情是spock创建了我的规范实例('this'),然后在使用weld / se的设置中我用select()创建了另一个.get()调用('我')。简单的printlns显示'me'!='this',实际上注入发生在通过select()。get()创建的托管实例上。或者我认为。

所以我认为我真正想要的是注射发生在'这个'上。一些谷歌搜索,我偶然发现:CDI inject into existing object这是类似的东西。我被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()
        }
    }
}

这很有效,而且我的规格更自然:

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
    }
}

现在要弄清楚这对任何事情都有好处....

2 个答案:

答案 0 :(得分:0)

根据更新2;我有一些工作。

答案 1 :(得分:0)

Update2存在性能问题:由于setup()在每个要素方法之前运行,因此每个要素方法都会对Weld进行初始化 - 使用扫描类路径和所有要素方法。

我将它移动到静态 - 但在这种情况下没有关闭(我在关闭钩子之外找不到它的位置,但可能甚至不需要测试):

class CdiSpecification extends Specification {

    private static Weld weld
    private static WeldContainer container
    private static BeanManager beanManager

    static {
        weld = new Weld()
        container = weld.initialize()
        beanManager = container.getBeanManager()
    }

    def setup() {
        CreationalContext<? extends CdiSpecification> creationalContext = beanManager.createCreationalContext(null)
        AnnotatedType<? extends CdiSpecification> annotatedType = beanManager.createAnnotatedType((Class<? extends CdiSpecification>) this.getClass())
        InjectionTarget<? extends CdiSpecification> injectionTarget = beanManager.createInjectionTarget(annotatedType)
        injectionTarget.inject(this, creationalContext);
    }

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