【问题标题】:Can't get Spock stubbing to accept a generated Closure无法让 Spock 存根接受生成的闭包
【发布时间】:2021-06-27 12:12:52
【问题描述】:

我正在编写 Spock 测试,并使用内联闭包来存根以实现简单的失败/通过行为。

    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'

【问题讨论】:

    标签: groovy closures spock


    【解决方案1】:

    Spock 严重依赖 AST 转换,因为有必要使用某些构造。

    1 * service.doSomething() &gt;&gt; x 只会返回 x

    1 * service.doSomething() &gt;&gt; { x } 将运行闭包中的代码并返回x

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

    def myClosure = {
      otherService.foo()
    }
    
    2 * service.doSomething() >> { myClosure() }
    

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

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

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

    【讨论】:

    • 谢谢。后来我意识到状态将不会被维持(我在想 Perl 成语)。然而,重点是避免响应链(这是我开始的地方)。
    • 只要将状态保持在闭包之外,它就可以工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-07-21
    • 2020-12-09
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    相关资源
    最近更新 更多