8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

使用 Dispatchers.Main.immediate(或 viewModelScope)更改 StateFlow 的值时,Flow 不会在测试中发出

scibuff 2月前

24 0

我调查了几个小时并搜索了网络(甚至打扰了 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。

帖子版权声明 1、本帖标题:使用 Dispatchers.Main.immediate(或 viewModelScope)更改 StateFlow 的值时,Flow 不会在测试中发出
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由scibuff在本站《kotlin》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您缺少有关 StateFlow 的一个关键细节:它的行为如同重播计数为 1 的混合流。

    这意味着只保证发出最新的值。

    通过连续执行“value=true value=false”(中间没有暂停),旧值就没有机会到达收集器。

    需要注意的是:(默认情况下)SharedFlow 不会合并,并且 emit() 会导致暂停,直到所有收集器处理完该值才会结束。StateFlow 的情况并非如此,因为它具有未指定的交付时间(因为 .value 可以从任何线程更改并且不会暂停)。

返回
作者最近主题: