如何从 Spock 测试中执行 CDI/SE?
How to do CDI/SE from Spock Test?
我一直在使用 CDIUnit 和其他各种形式的 CDI/SE 解决方案来实现测试 (junit),这些测试减少了模拟并使用了更多我的应用程序堆栈(我想是集成测试)。
无论如何,我也非常喜欢 Spock 进行测试,并认为应该很快将 CDI/SE space 和 spock 的东西混搭在一起,以便能够制定可以访问的规范大多数 CDI 的东西。
CDI 的许多单元运行器(CDIUnit、weldjunit、deltaspike、为 SE 执行 cdi 或焊接的随机博客片段)——是 JUnit 运行器,并且似乎与 Spock 的啮合不太好。经过多次修改后,我提炼成了一个非常简单的东西:weld/se + spock 和非常简单的@Inject。但它不起作用。
似乎 weld 确实 'start' 并且我的注射器的 post 构造函数触发了。然而,在 Spock 特征方法中对可注射物的引用为空。在进一步的测试中,我做了一个 @Inject setter 而不是实例变量,并且 setter 似乎确实触发了一个非空引用,但是当我的特性方法触发时;引用再次为空。我还弄乱了制作 Weld 和容器 @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
}
}
更新
我有点东西 "working"。不确定为什么或如何,也不确定它是否有任何好处(对于解决方案)。我想更多地了解发生了什么以及为什么。样品:
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
所以我 observed/surmised 真正发生的事情是 spock 创建了我的规范实例 ('this'),然后在使用 weld/se 的设置中我创建了另一个实例select().get() 调用 ('me')。简单的 printlns 显示 'me' != 'this' 并且实际上注入发生在通过 select().get() 创建的托管实例上。或者我认为。
所以我认为我真正想要的是在 'this' 上进行注入。一些谷歌搜索,我偶然发现了这个: CDI inject into existing object 这是类似的东西。我通过 DeltaSpike 的 injectFields 成为 'inspired' 并重构了 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;我有一些工作。
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()
// }
// }
}
我一直在使用 CDIUnit 和其他各种形式的 CDI/SE 解决方案来实现测试 (junit),这些测试减少了模拟并使用了更多我的应用程序堆栈(我想是集成测试)。
无论如何,我也非常喜欢 Spock 进行测试,并认为应该很快将 CDI/SE space 和 spock 的东西混搭在一起,以便能够制定可以访问的规范大多数 CDI 的东西。
CDI 的许多单元运行器(CDIUnit、weldjunit、deltaspike、为 SE 执行 cdi 或焊接的随机博客片段)——是 JUnit 运行器,并且似乎与 Spock 的啮合不太好。经过多次修改后,我提炼成了一个非常简单的东西:weld/se + spock 和非常简单的@Inject。但它不起作用。
似乎 weld 确实 'start' 并且我的注射器的 post 构造函数触发了。然而,在 Spock 特征方法中对可注射物的引用为空。在进一步的测试中,我做了一个 @Inject setter 而不是实例变量,并且 setter 似乎确实触发了一个非空引用,但是当我的特性方法触发时;引用再次为空。我还弄乱了制作 Weld 和容器 @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
}
}
更新
我有点东西 "working"。不确定为什么或如何,也不确定它是否有任何好处(对于解决方案)。我想更多地了解发生了什么以及为什么。样品:
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
所以我 observed/surmised 真正发生的事情是 spock 创建了我的规范实例 ('this'),然后在使用 weld/se 的设置中我创建了另一个实例select().get() 调用 ('me')。简单的 printlns 显示 'me' != 'this' 并且实际上注入发生在通过 select().get() 创建的托管实例上。或者我认为。
所以我认为我真正想要的是在 'this' 上进行注入。一些谷歌搜索,我偶然发现了这个: CDI inject into existing object 这是类似的东西。我通过 DeltaSpike 的 injectFields 成为 'inspired' 并重构了 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;我有一些工作。
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()
// }
// }
}