MainCoroutineRule and runBlocking of Kotlin Coroutines both are designed for testing purposes. And seems like both are offering the same functionality: running code synchronously in a test environment.
So what's the difference? What's the best use case for each of them?
MainCoroutineRule and runBlocking are seemingly similar but there are clear differences.
Defenition of MainCoroutineRule:
MainCoroutineRule installs a TestCoroutineDispatcher for Disptachers.Main. Since it extends TestCoroutineScope, you can directly launch coroutines on the MainCoroutineRule as a [CoroutineScope]...
Defenition of runBlocking:
Runs a new coroutine and blocks the current thread interruptibly until its completion. This function should not be used from a coroutine. It is designed to bridge regular blocking code to libraries that are written in suspending style, to be used in main functions and in tests. ...
In terms of definition, runBlocking is used for the sole purpose of synchronous execution in coroutines. It is not only used in tests but also used in UI management, Data Management, and several other areas in Android Development.
Whereas runBlocking is used more generally, MainCoroutineRule is used only in tests and it has the same synchronous execution behavior found in runBlocking. However, MainCoroutineRule has more specialized testing features not found in runBlocking such as control flow management. In addition, using MainCoroutineRule will significantly make your testing code cleaner.
In a much more detailed manner, MainCoroutineRule is directly related to JUnit Rule. If you have used JUnit before, you might remember filling out @Before @After to provide a testing environment for the test cases. If you have multiple test cases, you would eventually have to write multiple @Before @After to provide multiple testing environments, which could possibly lead to redundant boilerplate code. Now, this is where MainCoroutineRule shines! With MainCoroutineRule you can declare a testing environment once and reuse them for multiple test cases.
Compare two sample codes below:
Test case without using MainCoroutineRule
@ExperimentalCoroutinesApi
class MyViewModelTest {
private val testDispatcher = TestCoroutineDispatcher()
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
}
@After
fun tearDown() {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
@Test
fun testSomething() = runBlockingTest {
...
}
}
Test case using MainCoroutineRule
@ExperimentalCoroutinesApi
class MainCoroutineRule(
val testDispatcher: TestCoroutineDispatcher = TestCoroutineDispatcher()
) : TestWatcher() {
override fun starting(description: Description?) {
super.starting(description)
Dispatchers.setMain(testDispatcher)
}
override fun finished(description: Description?) {
super.finished(description)
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
}
@ExperimentalCoroutinesApi
fun MainCoroutineRule.runBlockingTest(block: suspend () -> Unit) =
this.testDispatcher.runBlockingTest {
block()
}
How convenient? This shows that Google actually cares for developers.
Let me know if you have any questions.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With