Reputation: 1158
When I separately run the runAsyncWithMock
test, it waits for 3 seconds until the mock's execution is finalised, rather than get terminated like the other 2 tests.
I was not able to figure out why.
It is interesting that:
Runnables
are executed by CompletableFuture.runAsync
in a row in the runAsyncWithMock
test, only the first one waits, the others not.runAsyncWithMock
tests, each and every of them runs for 3s when the whole specification is executed.Any idea what I got wrong?
My configuration:
The repo containing the whole Gradle project for reproduction:
https://github.com/lobodpav/CompletableFutureMisbehavingTestInSpock
The problematic test's code:
@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
}
}
Upvotes: 0
Views: 4207
Reputation: 13242
This is caused by the synchronized
methods in https://github.com/spockframework/spock/blob/master/spock-core/src/main/java/org/spockframework/mock/runtime/MockController.java when a mock is executed it delegates through the handle
method. The Specification also uses the synchronized
methods, in this case probably leaveScope
, and is thus blocked by the sleeping Stub method.
Since this is a thread interleaving problem I guess that additional closure in runAsyncWithMockAndClosure
moves the execution of the stub method behind the leaveScope
and thus changes the ordering/blocking.
Upvotes: 2
Reputation: 67417
Oh, just now after writing my last comment I saw a difference:
You use @Stepwise
(I didn't when I tried at first), an annotation I almost never use because it creates dependencies between feature methods (bad, bad testing practice). While I cannot say why this has the effect described by you only when running the first method, I can tell you that removing the annotation fixes it.
P.S.: With @Stepwise
you cannot even execute the second or third method separately because the runner will always run the preceding one(s) first, because - well, the specification is said to be executed step-wise. ;-)
Update: I could briefly reproduce the problem with @Stepwise
, but after recompilation now it does not happen anymore, neither with or without that annotation.
Upvotes: 0