MainCoroutineRule 和 runBlocking 的区别
Difference between MainCoroutineRule and runBlocking
Kotlin 协程的 MainCoroutineRule
和 runBlocking
都是为测试目的而设计的。似乎两者都提供相同的功能:运行 在测试环境中同步编码。
那么有什么区别呢?它们各自的最佳用例是什么?
MainCoroutineRule
和runBlocking
看似相似实则有明显区别
MainCoroutineRule installs a TestCoroutineDispatcher for Disptachers.Main. Since it extends TestCoroutineScope, you can directly launch coroutines on the MainCoroutineRule as a [CoroutineScope]...
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. ...
在定义上,runBlocking
仅用于协同程序中同步执行的目的。它不仅用于测试,还用于 UI 管理、数据管理和 Android 开发中的其他几个领域。
而 runBlocking
的使用更为普遍,而 MainCoroutineRule
仅在测试中使用,它具有与 runBlocking
相同的同步执行行为。但是,MainCoroutineRule
具有 runBlocking
中没有的更专业的测试功能,例如控制流管理。此外,使用 MainCoroutineRule
将使您的测试代码更清晰。
更详细地说,MainCoroutineRule 与 JUnit 规则直接相关。如果您以前使用过 JUnit,您可能还记得填写 @Before @After
为测试用例提供测试环境。如果你有多个测试用例,你最终将不得不编写多个 @Before @After
来提供多个测试环境,这可能会导致冗余的样板代码。现在,这就是 MainCoroutineRule
的亮点!使用 MainCoroutineRule
,您可以声明一次测试环境,然后将它们重复用于多个测试用例。
比较下面两个示例代码:
不使用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 {
...
}
}
使用 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()
}
方便吗?这表明Google其实很关心开发者。
如果您有任何问题,请告诉我。
MainCoroutineRule
和 runBlocking
都是为测试目的而设计的。似乎两者都提供相同的功能:运行 在测试环境中同步编码。
那么有什么区别呢?它们各自的最佳用例是什么?
MainCoroutineRule
和runBlocking
看似相似实则有明显区别
MainCoroutineRule installs a TestCoroutineDispatcher for Disptachers.Main. Since it extends TestCoroutineScope, you can directly launch coroutines on the MainCoroutineRule as a [CoroutineScope]...
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. ...
在定义上,runBlocking
仅用于协同程序中同步执行的目的。它不仅用于测试,还用于 UI 管理、数据管理和 Android 开发中的其他几个领域。
而 runBlocking
的使用更为普遍,而 MainCoroutineRule
仅在测试中使用,它具有与 runBlocking
相同的同步执行行为。但是,MainCoroutineRule
具有 runBlocking
中没有的更专业的测试功能,例如控制流管理。此外,使用 MainCoroutineRule
将使您的测试代码更清晰。
更详细地说,MainCoroutineRule 与 JUnit 规则直接相关。如果您以前使用过 JUnit,您可能还记得填写 @Before @After
为测试用例提供测试环境。如果你有多个测试用例,你最终将不得不编写多个 @Before @After
来提供多个测试环境,这可能会导致冗余的样板代码。现在,这就是 MainCoroutineRule
的亮点!使用 MainCoroutineRule
,您可以声明一次测试环境,然后将它们重复用于多个测试用例。
比较下面两个示例代码:
不使用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 {
...
}
}
使用 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()
}
方便吗?这表明Google其实很关心开发者。
如果您有任何问题,请告诉我。