Last active
December 12, 2023 08:36
-
-
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]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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