Testing 睡在斯波克';当CompletableFuture运行时,s模拟等待

Testing 睡在斯波克';当CompletableFuture运行时,s模拟等待,testing,groovy,spock,Testing,Groovy,Spock,当我单独运行runAsyncWithMock测试时,它会等待3秒钟,直到模拟的执行完成,而不是像其他两个测试一样被终止 我不知道为什么 有趣的是: 当CompletableFuture.runAsync在runAsyncWithMock测试中的一行中执行多个Runnables时,只有第一个等待,其他不等待 当有多个重复的runAsyncWithMock测试时,当整个规范执行时,每个测试都会运行3秒钟 当使用类实例而不是模拟时,测试将立即完成 知道我做错了什么吗 我的配置: 马科斯莫哈韦10.1

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

我不知道为什么

有趣的是:

  • CompletableFuture.runAsync
    runAsyncWithMock
    测试中的一行中执行多个
    Runnables
    时,只有第一个等待,其他不等待
  • 当有多个重复的
    runAsyncWithMock
    测试时,当整个规范执行时,每个测试都会运行3秒钟
  • 当使用类实例而不是模拟时,测试将立即完成
  • 知道我做错了什么吗

    我的配置:

    • 马科斯莫哈韦10.14.6
    • Spock 1.3-groovy-2.4
    • Groovy 2.4.15
    • JDK 1.8.0_201
    包含整个Gradle项目以供复制的回购协议:

    有问题的测试代码:

    @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
        }
    }
    

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

    您可以逐步使用
    @Stepwise
    (我刚开始尝试时没有使用),这是一个我几乎从未使用过的注释,因为它会在特性方法之间创建依赖关系(糟糕的测试实践)。虽然我无法解释为什么只有在运行第一个方法时才会产生您描述的效果,但我可以告诉您,删除注释可以修复它

    注意:
    @Stepwise
    您甚至不能单独执行第二个或第三个方法,因为运行程序总是首先运行前一个方法,因为-嗯,规范被称为是逐步执行的。;-)



    更新:我可以用
    @逐步地重现这个问题,但是在重新编译之后,无论是否有注释,它都不再发生了。

    哦,刚刚写下我的最后一条评论,我看到了一个不同点:

    您可以逐步使用
    @Stepwise
    (我刚开始尝试时没有使用),这是一个我几乎从未使用过的注释,因为它会在特性方法之间创建依赖关系(糟糕的测试实践)。虽然我无法解释为什么只有在运行第一个方法时才会产生您描述的效果,但我可以告诉您,删除注释可以修复它

    注意:
    @Stepwise
    您甚至不能单独执行第二个或第三个方法,因为运行程序总是首先运行前一个方法,因为-嗯,规范被称为是逐步执行的。;-)



    更新:我可以用
    @逐步地重现问题,但在重新编译后,无论是否使用该注释,问题都不会再发生。

    这是由中的
    同步
    方法造成的,当执行模拟时,它通过
    句柄
    方法进行委托。该规范还使用了
    synchronized
    方法,在本例中可能是
    leaveScope
    ,因此被休眠存根方法阻止


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

    这是由于执行mock时的
    synchronized
    方法导致的
    句柄
    方法。该规范还使用了
    synchronized
    方法,在本例中可能是
    leaveScope
    ,因此被休眠存根方法阻止


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

    我无法确认这一点。所有3个测试都会立即终止,测试执行甚至会在打印最终消息之前结束,大多数情况下甚至不会打印初始消息。如果我想查看所有消息,我必须执行如下操作:
    def future=CompletableFuture.runAsync(runnable);当(!future.done){sleep 100}
    时,您是否仅单独执行
    runAsyncWithMock
    测试?不是全部规格?我当然有。我分别运行了所有三种特性方法,并完成了整个测试。结果是一样的。与您的设置唯一不同的是,我使用的是Spock 1.3-groovy-2.5和groovy 2.5.7,但我不认为这会有任何区别。否则我也在Java8上,操作系统是Windows10.Hmm,那么我们的框架版本之间肯定会有一些变化。或者我,测试总是运行3秒。我不能确认。所有3个测试都会立即终止,测试执行甚至会在打印最终消息之前结束,大多数情况下甚至不会打印初始消息。如果我想查看所有消息,我必须执行如下操作:
    def future=CompletableFuture.runAsync(runnable);当(!future.done){sleep 100}
    时,您是否仅单独执行
    runAsyncWithMock
    测试?不是全部规格?我当然有。我分别运行了所有三种特性方法,并完成了整个测试。结果是一样的。与您的设置唯一不同的是,我使用的是Spock 1.3-groovy-2.5和groovy 2.5.7,但我不认为这会有任何区别。否则我也在Java8上,操作系统是Windows10.Hmm,那么我们的框架版本之间肯定会有一些变化。对我来说,测试总是运行3秒钟。我使用@Stepwise只是为了确保
    runasynchwithmock
    测试总是先执行,这样第一个测试总是需要3秒钟才能完成。无论如何,即使我在没有@Stepwise的情况下单独运行第一个测试,它也会运行3秒。然后请在GitHub上发布一个包含Maven构建(或Gradle作为第二选择),以便让问题对我重复。谢谢,我会做,并用链接更新问题。GitHub链接现在附在问题上。我可以与你一起重复