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