我调查了几个小时并搜索了网络(甚至打扰了 ChatGPT),但我很困惑这个问题还没有得到解决(显然我的知识非常有限)。所以这是设置:我有一个视图...
我调查了几个小时并搜索了网络(甚至打扰了 ChatGPT),但我很困惑,就我(显然非常有限的)知识而言,这个问题还没有得到解决。
因此,设置如下:我有一个带有 的视图模型, StateFlow
该模型在一个块内更新 launch { ... }
。在测试代码中,我无法让流程发出任何内容(初始值除外)。只有当我在生产代码中放置 yield()
或 delay()
调用时,它才会正确发出。
我将示例简化为其本质以重现该问题(只需复制粘贴即可运行):
@ExperimentalCoroutinesApi
class MyTest {
class MyViewModel {
private val _state = MutableStateFlow(false)
val state = _state.asStateFlow()
fun doSomething(runYield: Boolean) {
val viewModelScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) // btw. this is how Android provides a `viewModelScope`
viewModelScope.launch {
_state.value = true
// some workload here
if (runYield)
yield()
_state.value = false
}
}
}
@Before
fun setUp() {
Dispatchers.setMain(UnconfinedTestDispatcher())
}
@After
fun tearDown() {
Dispatchers.resetMain()
}
@Test
fun `Failing test`() = runTestCase(runYield = false)
@Test
fun `Passing test`() = runTestCase(runYield = true)
private fun runTestCase(runYield: Boolean) = runTest {
val viewModel = MyViewModel()
// Collect emissions to `state` in this mutable list
val testResults = mutableListOf<Boolean>()
// backgroundScope makes sure the job is shut down after the test
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.state.toList(testResults)
}
viewModel.doSomething(runYield)
assertEquals(listOf(false, true, false), testResults)
}
}
使用 a MutableSharedFlow
代替 the MutableStateFlow
也可以缓解该问题。
我花了很长时间才知道 yield()
或 delay()
调用可以缓解这个问题。但是:这到底是为什么呢?如果没有它我又如何解决这个问题呢?
使用 Kotlin 版本 1.9.10 和 Coroutines 核心+测试库 1.8.1。