Skip to content

Instantly share code, notes, and snippets.

@ywett02
Last active December 12, 2023 08:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ywett02/51cb0c9afaed21458feae79626c03f0f to your computer and use it in GitHub Desktop.
Save ywett02/51cb0c9afaed21458feae79626c03f0f to your computer and use it in GitHub Desktop.
Coroutine testing - examples using StandardTestDispatcher, UnconfinedTestDispatcher, TestsScope, and runTest [inspired by Kotlin Coroutines Deep Dive book]
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
fun main() {
println("--- StandardTestDispatcher: 1. example ---")
println("--- When virtual time is not advanced, coroutine is not executed ---")
standardTestDispatcherExample1()
println()
println("--- StandardTestDispatcher: 2. example ---")
println("--- Example of advancing time to execute coroutine ---")
standardTestDispatcherExample2()
println()
println("--- TestScope: 1. example ---")
println("--- When virtual time is not advanced, coroutine is not executed ---")
testScopeExample1()
println()
println("--- TestScope: 2. example ---")
println("--- Example of advancing time to execute coroutine ---")
testScopeExample2()
println()
println("--- runTest: 1. example ---")
println("--- When virtual time is not advanced manually, the lambda is executed sequentially ---")
runTestExample1()
println()
println("--- runTest: 2. example ---")
println("--- Example of advancing time ---")
runTestExample2()
println()
println("--- runTest: 3. example ---")
println("--- When virtual time is not advanced manually, the coroutine is executed at the end ---")
runTestExample3()
println()
println("--- runTest: 4. example ---")
println("--- Example of advancing time to execute coroutine ---")
runTestExample4()
println()
println("--- UnconfinedTestDispatcher: 1. example ---")
println("--- When virtual time is not advanced, coroutine is executed until the first suspension point ---")
unconfinedTestDispatcherExample1()
println()
println("--- UnconfinedTestDispatcher: 2. example ---")
println("--- Example of advancing time to execute coroutine ---")
unconfinedTestDispatcherExample2()
println()
println("--- TestScope(UnconfinedTestDispatcher): 1. example ---")
println("--- When virtual time is not advanced, coroutine is executed until the first suspension point ---")
testScopeUnconfinedTestDispatcherExample1()
println()
println("--- TestScope(UnconfinedTestDispatcher): 2. example ---")
println("--- Example of advancing time to execute coroutine ---")
testScopeUnconfinedTestDispatcherExample2()
println()
println("--- runTest(UnconfinedTestDispatcher): 1. example ---")
println("--- When virtual time is not advanced manually, the lambda is executed sequentially ---")
runTestUnconfinedTestDispatcherExample1()
println()
println("--- runTest(UnconfinedTestDispatcher): 2. example ---")
println("--- Example of advancing time ---")
runTestUnconfinedTestDispatcherExample2()
println()
println("--- runTest(UnconfinedTestDispatcher): 3. example ---")
println(
"--- When virtual time is not advanced manually, " +
"the coroutine is executed until the first suspension point and continues at the end---"
)
runTestUnconfinedTestDispatcherExample3()
println()
println("--- runTest(UnconfinedTestDispatcher): 4. example ---")
println("--- Example of advancing time to execute coroutine ---")
runTestUnconfinedTestDispatcherExample4()
println()
}
/**
* StandardTestDispatcher: 1. example
*
* When virtual time is not advanced, coroutine is not executed.
*/
fun standardTestDispatcherExample1() {
val standardTestDispatcher = StandardTestDispatcher()
CoroutineScope(standardTestDispatcher).launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Function finished")
}
/**
* StandardTestDispatcher: 2. example
*
* Example of advancing time to execute coroutine.
*/
fun standardTestDispatcherExample2() {
val standardTestDispatcher = StandardTestDispatcher()
CoroutineScope(standardTestDispatcher).launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${standardTestDispatcher.scheduler.currentTime}")
standardTestDispatcher.scheduler.advanceTimeBy(1000)
println("Current time: ${standardTestDispatcher.scheduler.currentTime}")
standardTestDispatcher.scheduler.runCurrent()
standardTestDispatcher.scheduler.advanceUntilIdle()
println("Current time: ${standardTestDispatcher.scheduler.currentTime}")
println("Function finished")
}
/**
* TestScope: 1. example
*
* In the previous examples, we were using StandardTestDispatcher and wrapping it with a scope.
* Instead, we can use TestScope, which does the same.
*
* When virtual time is not advanced, coroutine is not executed.
*/
fun testScopeExample1() {
val testScope = TestScope()
testScope.launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Function finished")
}
/**
* TestScope: 2. example
*
* In the previous examples, we were using StandardTestDispatcher and wrapping it with a scope.
* Instead, we can use TestScope, which does the same.
*
* Example of advancing time to execute coroutine.
*/
fun testScopeExample2() {
val testScope = TestScope()
testScope.launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScope.testScheduler.currentTime}")
testScope.testScheduler.advanceTimeBy(1000)
println("Current time: $testScope.testScheduler.currentTime}")
testScope.testScheduler.runCurrent()
testScope.testScheduler.advanceUntilIdle()
println("Current time: ${testScope.testScheduler.currentTime}")
println("Function finished")
}
/**
* runTest: 1. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* When virtual time is not advanced manually, the lambda is executed sequentially.
*/
fun runTestExample1() {
runTest {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
println("Execution reached the line after doing the main work")
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
/**
* runTest: 2. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* Example of advancing time.
*/
fun runTestExample2() {
runTest {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
println("Execution reached the line after doing the main work")
println("Current time: ${testScheduler.currentTime}")
testScheduler.advanceTimeBy(1000)
println("Current time: ${testScheduler.currentTime}")
testScheduler.runCurrent()
testScheduler.advanceUntilIdle()
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
/**
* runTest: 3. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* When virtual time is not advanced manually, the coroutine is executed at the end.
*/
fun runTestExample3() {
runTest {
launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScheduler.currentTime}")
println("Function finished ")
}
}
/**
* runTest: 4. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* Example of advancing time to execute coroutine.
*/
fun runTestExample4() {
runTest {
launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScheduler.currentTime}")
testScheduler.advanceTimeBy(1000)
println("Current time: ${testScheduler.currentTime}")
testScheduler.runCurrent()
testScheduler.advanceUntilIdle()
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
/**
* UnconfinedTestDispatcher: 1. example
*
* When virtual time is not advanced, coroutine is executed until the first suspension point.
*/
fun unconfinedTestDispatcherExample1() {
val unconfinedTestDispatcher = UnconfinedTestDispatcher()
CoroutineScope(unconfinedTestDispatcher).launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Function finished")
}
/**
* UnconfinedTestDispatcher: 2. example
*
* Example of advancing time to execute coroutine.
*/
fun unconfinedTestDispatcherExample2() {
val unconfinedTestDispatcher = UnconfinedTestDispatcher()
CoroutineScope(unconfinedTestDispatcher).launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${unconfinedTestDispatcher.scheduler.currentTime}")
unconfinedTestDispatcher.scheduler.advanceTimeBy(1000)
println("Current time: ${unconfinedTestDispatcher.scheduler.currentTime}")
unconfinedTestDispatcher.scheduler.runCurrent()
unconfinedTestDispatcher.scheduler.advanceUntilIdle()
println("Current time: ${unconfinedTestDispatcher.scheduler.currentTime}")
println("Function finished")
}
/**
* TestScope(UnconfinedTestDispatcher): 1. example
*
* When virtual time is not advanced, coroutine is executed until the first suspension point.
*/
fun testScopeUnconfinedTestDispatcherExample1() {
val testScope = TestScope(UnconfinedTestDispatcher())
testScope.launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Function finished")
}
/**
* TestScope(UnconfinedTestDispatcher): 2. example
*
* Example of advancing time to execute coroutine.
*/
fun testScopeUnconfinedTestDispatcherExample2() {
val testScope = TestScope(UnconfinedTestDispatcher())
testScope.launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScope.testScheduler.currentTime}")
testScope.testScheduler.advanceTimeBy(1000)
println("Current time: ${testScope.testScheduler.currentTime}")
testScope.testScheduler.runCurrent()
testScope.testScheduler.advanceUntilIdle()
println("Current time: ${testScope.testScheduler.currentTime}")
println("Function finished")
}
/**
* runTest(UnconfinedTestDispatcher): 1. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* When virtual time is not advanced manually, the lambda is executed sequentially.
*/
fun runTestUnconfinedTestDispatcherExample1() {
runTest(UnconfinedTestDispatcher()) {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
println("Execution reached the line after doing the main work")
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
/**
* runTest(UnconfinedTestDispatcher): 2. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* Example of advancing time.
*/
fun runTestUnconfinedTestDispatcherExample2() {
runTest(UnconfinedTestDispatcher()) {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
println("Execution reached the line after doing the main work")
println("Current time: ${testScheduler.currentTime}")
testScheduler.advanceTimeBy(1000)
println("Current time: ${testScheduler.currentTime}")
testScheduler.runCurrent()
testScheduler.advanceUntilIdle()
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
/**
* runTest(UnconfinedTestDispatcher): 3. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* When virtual time is not advanced manually, the coroutine is executed until the first suspension point.
*/
fun runTestUnconfinedTestDispatcherExample3() {
runTest(UnconfinedTestDispatcher()) {
launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScheduler.currentTime}")
println("Function finished ")
}
}
/**
* runTest(UnconfinedTestDispatcher): 4. example
*
* [runTest] starts a coroutine with TestScope and immediately advances it until idle.
*
* Example of advancing time to execute coroutine.
*/
fun runTestUnconfinedTestDispatcherExample4() {
runTest(UnconfinedTestDispatcher()) {
launch {
println("Some work 1")
delay(1000)
println("Some work 2")
delay(1000)
println("Coroutine done")
}
println("Execution reached the line after launching coroutine")
println("Current time: ${testScheduler.currentTime}")
testScheduler.advanceTimeBy(1000)
println("Current time: ${testScheduler.currentTime}")
testScheduler.runCurrent()
testScheduler.advanceUntilIdle()
println("Current time: ${testScheduler.currentTime}")
println("Function finished")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment