无法让 Spock 存根以接受生成的闭包

Can't get Spock stubbing to accept a generated Closure

我正在编写 Spock 测试,并使用内联闭包来对简单的 fail/pass 行为进行存根。

    def "test timeout"() {
        given:

        2 * feignClient.poll("foo") >>
                {
                    int retries = 0;
                    if (retries < 1) {
                        retries++
                        throw newRetryable()
                    }
                    pollWaitSuccessResponseEntity
                }

所以我尝试将闭包重构为命名闭包:

        def retryClosure = {
                    int retries = 0;
                    if (retries < 1) {
                        retries++
                        throw newRetryable()
                    }
                    pollWaitSuccessResponseEntity
                }
        2 * feignClient.poll("foo") >> retryClosure

测试失败并出现以下错误:

Caused by: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object
 'com.example.service.FooServiceTest$__spock_initializeFields_closure2@3243178c' with class 'com.example..FooServiceTest$__spock_initializeFields_closure2' to class 'org.springframework.http.ResponseEntity'

Spock 严重依赖 AST 转换,因为必须使用某些结构。

1 * service.doSomething() >> x 只会 return x

1 * service.doSomething() >> { x } 将 运行 闭包中的代码和 return x

因此,如果您想延迟响应代码的执行,但仍想将它放在一个变量中,您需要将执行包装在一个闭包中。

def myClosure = {
  otherService.foo()
}

2 * service.doSomething() >> { myClosure() }

只知道您可以改用响应链。

2 * feignClient.poll("foo") >> { throw newRetryable() } >> pollWaitSuccessResponseEntity

您的闭包代码的主要问题是您将状态保留在闭包内,因此每次调用都会重置它。您需要将重试计数器移出闭包,以便在调用之间保持状态。