Spock的Mock中的睡眠由CompletableFuture运行时等待

时间:2019-09-10 10:51:20

标签: testing groovy spock

当我分别运行runAsyncWithMock测试时,它会等待3秒钟,直到模拟的执行完成为止,而不是像其他两个测试一样被终止。

我不知道为什么。

有趣的是:

  1. Runnables测试中,CompletableFuture.runAsync连续执行了多个runAsyncWithMock时,只有第一个等待,其他则没有。
  2. 如果有多个重复的runAsyncWithMock测试,则在执行整个规范时,每个测试都将运行3秒钟。
  3. 使用Class实例而不是Mock时,测试将立即完成。

知道我怎么了吗?

我的配置:

  • macOS Mojave 10.14.6
  • Spock 1.3-groovy-2.4
  • Groovy 2.4.15
  • JDK 1.8.0_201

回购包含整个Gradle项目以进行复制:

https://github.com/lobodpav/CompletableFutureMisbehavingTestInSpock

有问题的测试代码:

@Stepwise
class SpockCompletableFutureTest extends Specification {
    def runnable = Stub(Runnable) {
        run() >> {
            println "${Date.newInstance()} BEGIN1 in thread ${Thread.currentThread()}"
            sleep(3000)
            println "${Date.newInstance()} END1   in thread ${Thread.currentThread()}"
        }
    }

    def "runAsyncWithMock"() {
        when:
        CompletableFuture.runAsync(runnable)

        then:
        true
    }

    def "runAsyncWithMockAndClosure"() {
        when:
        CompletableFuture.runAsync({ runnable.run() })

        then:
        true
    }

    def "runAsyncWithClass"() {
        when:
        CompletableFuture.runAsync(new Runnable() {
            void run() {
                println "${Date.newInstance()} BEGIN2 in thread ${Thread.currentThread()}"
                sleep(3000)
                println "${Date.newInstance()} END2   in thread ${Thread.currentThread()}"
            }
        })

        then:
        true
    }
}

2 个答案:

答案 0 :(得分:1)

这是由https://github.com/spockframework/spock/blob/master/spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java中的synchronized方法引起的,当执行模拟时,它通过handle方法进行委托。该规范还使用synchronized方法,在这种情况下可能使用leaveScope,因此被休眠Stub方法阻止。

由于这是一个线程交错问题,我猜想runAsyncWithMockAndClosure中的附加闭包将存根方法的执行移到了leaveScope之后,从而改变了顺序/阻塞。

答案 1 :(得分:0)

哦,刚才写完最后一条评论后,我看到了一个不同:

您使用localStorage.setItem('nameoffield',value); (初次尝试时没有使用),我几乎从未使用过它,因为它会在功能方法之间建立依赖关系(不良,不良的测试实践)。虽然我不能说为什么只有在运行第一种方法时,这种效果才会由您描述,但是我可以告诉您,删除注释可以解决此问题。

P.S .:使用@Stepwise时,您甚至不能单独执行第二种或第三种方法,因为运行程序将始终首先运行前面的方法,因为-好吧,据说该规范是逐步执行的。 ;-)


更新:我可以使用@Stepwise简要地重现该问题,但是重新编译后,无论有没有注释,现在都不再发生。