如何测试ViewModel初始化阶段发射的StateFlow与SharedFlow值
解决方案
核心思路
通过控制测试协程调度器的执行时机,阻止ViewModel初始化时的协程立即执行,等你完成对两个Flow的订阅后再恢复调度,就能捕获到初始化逻辑中发射的所有事件。
前置依赖
确保项目引入了kotlinx-coroutines-test测试依赖,版本1.6.0及以上即可。
测试代码示例
@OptIn(ExperimentalCoroutinesApi::class) class MyViewModelTest { // 测试网络请求成功场景 @Test fun `init network call success emits expected state`() = runTest { // 模拟网络请求成功,返回预期的新状态 val expectedNewState = LoadSuccessState(data = "test") mockNetworkSuccess(expectedNewState) // 暂停调度器,阻止初始化协程立即执行 testScheduler.pauseDispatcher() // 创建ViewModel,此时performNetworkCall不会执行 val viewModel = MyViewModel<ViewState>(initialState = LoadingState) viewModel.state.test { viewModel.errorFlow.test { // 恢复调度器,开始执行初始化逻辑 testScheduler.resumeDispatcher() // 验证StateFlow先发射初始状态,再发射成功后的新状态 assertEquals(LoadingState, awaitItem()) assertEquals(expectedNewState, awaitItem()) // 验证errorFlow没有发射任何事件 expectNoEvents() } } } // 测试网络请求失败场景 @Test fun `init network call failure emits error event`() = runTest { // 模拟网络请求失败 mockNetworkFailure() testScheduler.pauseDispatcher() val viewModel = MyViewModel<ViewState>(initialState = LoadingState) viewModel.state.test { viewModel.errorFlow.test { testScheduler.resumeDispatcher() // 验证StateFlow仅发射初始状态,无后续更新 assertEquals(LoadingState, awaitItem()) expectNoEvents() // 验证errorFlow发射预期错误信息 assertEquals("network failure", awaitItem()) } } } // 模拟网络请求成功,此处以MockK为例,Mockito写法逻辑一致 private fun mockNetworkSuccess(returnState: ViewState) { coEvery { Network.makeCall(eq("/someEndpoint"), any(), any()) } answers { secondArg<(ViewState) -> Unit>().invoke(returnState) } } // 模拟网络请求失败 private fun mockNetworkFailure() { coEvery { Network.makeCall(eq("/someEndpoint"), any(), any()) } answers { thirdArg<() -> Unit>().invoke() } } }
补充说明
- 如果你只需要验证
state的最终值,不需要校验中间状态,不需要暂停调度器,直接在ViewModel创建完成后调用viewModel.state.first()获取最新值断言即可,因为StateFlow本身会持有最新状态。 - 如果你业务逻辑允许新订阅者获取之前的错误事件,也可以把
errorFlow的replay属性设置为1:val errorFlow: SharedFlow<String> = MutableSharedFlow(replay = 1),这种情况下不需要暂停调度器,初始化完成后订阅也能拿到之前发射的错误值,注意该修改会改变生产环境的行为,需要确认符合产品需求。
内容的提问来源于stack exchange,提问作者devtheory3
相关产品推荐
相关产品推荐

