Java 如何使用私有财产创建Spock Spy
我有以下Java类:Java 如何使用私有财产创建Spock Spy,java,groovy,spock,Java,Groovy,Spock,我有以下Java类: public class FooServiceImpl { private BarService barService; public String generateFoo() { String barValue = barService.generateBar(); return customFoo() + barValue; } public String customFoo() { re
public class FooServiceImpl {
private BarService barService;
public String generateFoo() {
String barValue = barService.generateBar();
return customFoo() + barValue;
}
public String customFoo() {
return "abc";
}
}
这里是示例性Spock试验方法:
def "generate foo bar"() {
setup:
def barService = Mock(BarService) {
generateBar() >> "Bar"
}
FooServiceImpl spyFooService =
Spy(FooServiceImpl, constructorArgs: [[barService: barService]])
spyFooService.customFoo() >> "foo"
when:
def fooValue = spyFooService.generateFoo()
then:
fooValue == "fooBar"
}
我试图为FooServiceImpl
类创建一个间谍对象,但出现以下错误:
org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack:
No such property: barService for class:
com.foo.FooServiceImpl$$EnhancerByCGL`
我无法将构造函数添加到FooServiceImpl
或BarService
的setter,因此我想使用map构造函数。这可能吗
注意:根据它应该起作用在您的情况下,最简单的解决方案是将此字段
设置为受保护的
,而不是私有的
。当您从类创建spy对象时,涉及CGLIB,它从您试图从中创建spy的类中创建子类-com.foo.FooServiceImpl$$EnhancerByCGL
。问题是您试图修改的字段是私有字段,根据Java中的常规子类化策略,私有字段不会在子类中继承。这就是spy对象中不存在字段barService
的原因
注意:IntelliJ的调试器可能会告诉您,barService
存在于这个spyFromService
实例中,然而,这是IDE的错误-如果您列出了spyFromService.class.fields
或spyFromService.class.declaredFields
中的所有可用字段,您将无法在此处找到barService
字段
另一个问题是,当CGLIB参与对象创建过程时,如果涉及到调用方法,它也会参与。这就是为什么通过Groovy的元编程特性向类或实例添加动态字段是行不通的。否则,您将能够执行以下操作:
spyFromService.metaClass.barService = barService
或
或者,您可以去掉spy对象,并在测试中使用真实实例。然后
FooServiceImpl spyFromService = new FooServiceImpl()
spyFromService.@barService = barService
会有用的。但是,您将无法存根现有的customFoo()
方法,您将不得不依赖其实际实现返回的内容
FooServiceImpl spyFromService = new FooServiceImpl()
spyFromService.@barService = barService