Groovy 每个实例的元类方法重写在 Spock 测试中没有按预期工作

Groovy per instance metaClass method override doesn't work as expected in Spock test

我有一个 class 方法叫做 execute()。在一些 Spock 单元测试中,我模拟了 execute 方法并给它一个像这样的模拟闭包:

def setup () {
    rule = new DynamicRule ()
}

def "test default execution " (){
    given : "basic AORule "
    def mockres
    rule.metaClass.execute = {-> mockres = "did nothing"}     //mock the action
    def res = rule.execute()


    expect : "execute should do nothing "
    mockres == "did nothing"

}

如果我 运行 这个测试失败了。在 idea 编辑器中,模拟闭包显示为带下划线的,但下一行的 rule.execute() 不是 - 所以它可以看到方法。

如果我为此更改此测试:

    rule.metaClass.execute2 = {-> mockres = "did nothing"}     //mock the action
    def res = rule.execute2()

然后测试通过。

在 Spock 之外,我只是 运行 一个简单的 Groovy 脚本,并做了方法重载,并且正如我所期望的那样正常工作,并且该方法是用闭包模拟的

class A {
    def execute () {
        println "thing"
    }
}

def c = new A()
def res
c.execute()

c.metaClass.execute  = {-> res =2 ; println "modified thing "; }

c.execute ()

println "res = "+  res

为什么 Spock 测试中没有出现同样的情况?

单元存根如何为 Spock 正确测试闭包?

此修改版本测试成功:

def "test default execution " (){
    given : "basic AORule "

    def mockres

    def stub = new StubFor(AORule)
    stub.demand.execute { mockres = "did nothing" }
//        rule.metaClass.execute = {-> mockres = "did nothing"}     //mock the action
//        def res = rule.execute()

    expect : "execute should do nothing "
    stub.use {
        rule.execute()
        mockres == "did nothing"

    }
}

为什么简单的 per metaclass 在 Spock 中不起作用?

这是 Groovy >= 2.4.3 上的未决问题,此处:GROOVY-7368

用元类覆盖私有方法时存在错误。