with-runTest
Example using runTest to control virtual time in tests.
Code
package com.glassthought.sandbox
import com.glassthought.sandbox.impl.CustomDescribeSpec
import com.glassthought.sandbox.util.out.impl.out
import io.kotest.matchers.shouldBe
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.advanceTimeBy
import kotlinx.coroutines.test.advanceUntilIdle
import kotlinx.coroutines.test.runTest
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds
/** Shows basics of using runTest so that functions like 'delay' become virtual timed. */
@OptIn(ExperimentalCoroutinesApi::class)
class VirtualTimeDescribeSpec : CustomDescribeSpec({
describe("Timer Service") {
it("should complete instantly with virtual time") {
runTest {
var done = false
out.info("advanceUntilIdle() auto advances")
launch {
out.delay(5.seconds) // Would normally take 5 seconds
done = true
}
// Time jumps forward instantly
advanceUntilIdle()
done shouldBe true
}
}
it("should control time step by step") {
runTest {
var counter = 0
out.info("advanceTimeBy() gives precise control.")
launch {
out.delay(1.seconds)
counter++
out.delay(1.seconds)
counter++
}
advanceTimeBy(1100.milliseconds)
counter shouldBe 1
advanceTimeBy(1100.milliseconds)
counter shouldBe 2
}
}
}
})
private var count = 0
private suspend fun incrementCountAndPrint(string: String) {
count += 1
out.info("[${count}]: ${string}")
}
private suspend fun incrementAndPrintForIt(msg: String) {
incrementCountAndPrint(msg)
out.info("")
}
Command to reproduce:
gt.sandbox.checkout.commit 680dd5e9e988c8ebec90 \
&& cd "${GT_SANDBOX_REPO}" \
&& cmd.run.announce "./gradlew test --rerun-tasks"
Recorded output of command:
Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
> Task :app:checkKotlinGradlePluginConfigurationErrors SKIPPED
> Task :app:processResources NO-SOURCE
> Task :app:processTestResources NO-SOURCE
> Task :app:compileKotlin
> Task :app:compileJava NO-SOURCE
> Task :app:classes UP-TO-DATE
> Task :app:compileTestKotlin
> Task :app:compileTestJava NO-SOURCE
> Task :app:testClasses UP-TO-DATE
> Task :app:test
Picked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debug
Gradle Test Executor 1 STANDARD_OUT
Warning: Kotest autoscan is enabled. This means Kotest will scan the classpath for extensions that are annotated with @AutoScan. To avoid this startup cost, disable autoscan by setting the system property 'kotest.framework.classpath.scanning.autoscan.disable=true'. In 6.0 this value will default to true. For further details see https://kotest.io/docs/next/framework/project-config.html#runtime-detection
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should complete instantly with virtual time STARTED
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should complete instantly with virtual time STANDARD_OUT
[INFO][elapsed: 38ms][①][coroutname:@kotlinx.coroutines.test runner#5] advanceUntilIdle() auto advances
[INFO][elapsed: 42ms][⓶][coroutname:@coroutine#6] [🐢] Delaying for [5s]
[INFO][elapsed: 43ms][⓶][coroutname:@coroutine#6] Done delaying for [5s]
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should complete instantly with virtual time PASSED
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should control time step by step STARTED
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should control time step by step STANDARD_OUT
[INFO][elapsed: 52ms][⓷][coroutname:@kotlinx.coroutines.test runner#8] advanceTimeBy() gives precise control.
[INFO][elapsed: 52ms][⓸][coroutname:@coroutine#9] [🐢] Delaying for [1s]
[INFO][elapsed: 52ms][⓸][coroutname:@coroutine#9] Done delaying for [1s]
[INFO][elapsed: 52ms][⓸][coroutname:@coroutine#9] [🐢] Delaying for [1s]
[INFO][elapsed: 52ms][⓸][coroutname:@coroutine#9] Done delaying for [1s]
com.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should control time step by step PASSED
BUILD SUCCESSFUL in 2s
3 actionable tasks: 3 executed
Backlinks