Example using runTest to control virtual time in tests.
Code
package com.glassthought.sandboximport com.glassthought.sandbox.impl.CustomDescribeSpecimport com.glassthought.sandbox.util.out.impl.outimport io.kotest.matchers.shouldBeimport kotlinx.coroutines.ExperimentalCoroutinesApiimport kotlinx.coroutines.launchimport kotlinx.coroutines.test.advanceTimeByimport kotlinx.coroutines.test.advanceUntilIdleimport kotlinx.coroutines.test.runTestimport kotlin.time.Duration.Companion.millisecondsimport 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 = 0private 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:testPicked up JAVA_TOOL_OPTIONS: -Dkotlinx.coroutines.debugGradle 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-detectioncom.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should complete instantly with virtual time STARTEDcom.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 PASSEDcom.glassthought.sandbox.VirtualTimeDescribeSpec > Timer Service > should control time step by step STARTEDcom.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 PASSEDBUILD SUCCESSFUL in 2s3 actionable tasks: 3 executed