java - 如何使用私有(private)属性(property)创建 Spock Spy

标签 java groovy spock

我有以下Java类:

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 创建一个 Spy 对象上课,但我收到以下错误:
org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack: 
No such property: barService for class: 
com.foo.FooServiceImpl$$EnhancerByCGL`

我无法向 FooServiceImpl 添加构造函数或 BarService 的二传手,所以我想使用 map 构造函数。这可能吗?

注:根据this issue它应该工作

最佳答案

在您的情况下,最简单的解决方案是将此字段设为 protected而不是 private .当你从一个类创建一个 spy 对象时,CGLIB 被涉及,它从你试图创建 spy 的类创建为子类 - com.foo.FooServiceImpl$$EnhancerByCGL在你的情况下。问题是您要修改的字段是私有(private)字段,并且根据 Java 中的常规子类化策略,私有(private)字段不会在子类中继承。这就是为什么字段 barService spy 对象中不存在

ATTENTION: IntelliJ's debugger may tell you that barService is present in this spyFromService instance, however this is IDE's bug - if you list all available fields from spyFromService.class.fields or spyFromService.class.declaredFields you wont find barService field here.



另一个问题是,当 CGLIB 参与对象创建过程时,如果涉及到调用方法,它也会参与其中。这就是为什么通过 Groovy 的元编程功能向类或实例添加动态字段不起作用的原因。否则,您将能够执行以下操作:
spyFromService.metaClass.barService = barService

或者
spyFromService.class.metaClass.barService = barService

或者,您可以摆脱 spy 对象并在测试中使用真实实例。然后
FooServiceImpl spyFromService = new FooServiceImpl()
spyFromService.@barService = barService

将工作。但是,您将无法 stub 现有的 customFoo()方法,您将不得不依赖其实际实现返回的内容。

关于java - 如何使用私有(private)属性(property)创建 Spock Spy,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49818211/

相关文章:

java - 使用 Gradle 和 Groovy/Spock 测试 Java 6 库或应用程序

java - 为什么在找不到主要方法时不生成异常或错误?

常规分割异常 java.lang.ArrayIndexOutOfBoundsException : 1

java - Groovy Spock 与 java 测试类

java - Spock 认为测试类的内部枚举应该是 Spec 的属性

string - Groovy 中使用 "body"进行高效字符串替换策略

java - 如何在 JUnit 测试中保存 Log4j 发送到 STDOUT 的输出?

java - 使用 AbstractTableModel 在 Jtable 中添加行

java - Google Apps Engine - 有关 ImageService url 服务的一些问题

java - 如何合并 2 个 groovy 脚本形式的 groovy 配置文件?