【问题标题】:Spock Metaprogramming getProperty()Spock 元编程 getProperty()
【发布时间】:2019-05-13 23:19:42
【问题描述】:

根据get/setProperty 的文档,我想在Spock 测试中覆盖getProperty() 方法。这在普通的 Groovy 类中是微不足道的,但在 Spock 规范中似乎不起作用。

class MainSpec extends Specification {
    @Override
    def getProperty(String name) {
        def value = metaClass.getProperty(this, name)
        println "$name == $value"
        return value
    }

    String foo = 'foo'

    def test() {
        expect:
        foo
        println foo
    }
}

此示例不调用getProperty() 方法。看来Spock不知何故绕过了它。有没有办法挂钩 Spock 的属性解析机制,或者告诉 Spock 使用我重写的方法?

【问题讨论】:

  • 请问这个用例是什么?
  • 我有一个包含大量属性的集成规范,这些属性基本上代表了外部系统中的标识符。这些 ID 映射到的数据是不稳定的,但我可以提前验证所有属性,并通过拦截它们的 getProperty() 调用来缩短更昂贵的测试。至少,对于包含错误数据的测试,这会给我一个一致的失败消息。
  • Spock 使用 AST 转换并编译规范,无需进一步研究,我猜测它不使用 groovy MOP 来处理本地定义的属性。为什么不使用可以使用普通元编程的属性持有者类,它还可以更好地分离您的逻辑。

标签: groovy metaprogramming spock


【解决方案1】:

是的,您可以使用“Expando”样式,其中属性不应在 Spec 类中定义,而是存储在映射 (storage) 中并由 setPropertygetProperty 方法操作:

class MetaprogrammingSpec extends Specification {
    def storage = [:]

    @Override
    def getProperty(String name) {
        def value = storage[name]
        println "$name == $value"
        return value
    }

    @Override
    void setProperty(String name, value) {
        storage[name] = value
    }

    def test() {
        when:
        foo = 'bar'

        then:
        foo
        println foo
    }
}

那么结果是:

评论后更新:getProperty() 方法在你不初始化foo 属性时也会被调用。当您以这种方式更改测试时:

def test() {
    expect:
    foo
    println foo
}

结果如预期 - 调用了 getProperty() 但测试失败,因为 foonull

【讨论】:

  • 这似乎只是因为foo 是一个未解析的符号。在其赋值前添加def,不再调用getProperty()
  • 如果添加 def,foo 是方法的本地,所以不是属性
  • 正如@tim_yates 所说,如果您添加def,那么它将是该方法的本地并且无法调用getProperty()。查看答案更新 - 当您删除带有 foo 赋值的 when 部分时,也会调用 getProperty()
  • 谢谢,我猜局部变量的变化很明显;但我仍然很难理解为什么不能在规范中声明该属性。
【解决方案2】:

事实证明,将属性移动到父类足以使其通过getProperty() 拦截器,即使父类是另一个Specification 类。

class BaseSpec extends Specification {
    def foo = 'foo'
}

class MainSpec extends BaseSpec {
    @Override
    def getProperty(String name) {
        def value = super.getProperty(name)
        println "$name == $value"
        return value
    }

    def test() {
        expect:
        foo
        println foo
    }
}

【讨论】:

    猜你喜欢
    • 2019-09-25
    • 1970-01-01
    • 2016-10-15
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 2016-02-22
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多