You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在协程中测试获取StateFlow全部状态值(无需delay)

StateFlow测试无法捕获加载状态的解决方案

测试StateFlow时,始终仅能接收到初始状态和成功状态,无法获取LoaderType对应的加载状态;若不使用delay()函数,测试用例会持续失败。以下是无需依赖delay()即可成功获取所有状态的测试方案:

失败的实现代码

fun getExhibitions(loaderType: LoaderType) {
    viewModelScope.launch {
        state.update { it.loading(loaderType) } // #1 切换为加载状态

        val result = useCase.getExhibitions(
            params = GetExhibitionsUseCase.Params(shopId, sellerId)
        )

        when (result) {
            is UseCaseResult.Success -> {
                val displayModel = mapper.mapExhibitionList(result.value)
                state.update { it.loadingSuccess(displayModel.exhibitions) } // #2 切换为成功状态
            }
            is UseCaseResult.Fail -> {
                onErrorGetExhibitions(result.throwable)
            }
        }
    }
}

测试代码

@Test
fun load_success() = runTest {

    // given
    prepareViewModel_success()

    viewModel.uiState.test {

        // 初始状态断言
        assert((awaitItem() as UiState.Loading).loaderType == QCommerceLoaderType.NONE)

        // 触发加载
        viewModel.getExhibitions(loaderTyp = LoaderType.TEXT)

        // 验证状态
        assert((awaitItem() as UiState.Loading).loaderType == QCommerceLoaderType.TEXT) // 此处测试失败
        assert((awaitItem() as UiState.Success).exhibitions.isNotEmpty())
    }

}

可行的修改方案

方案一:添加delay()(不推荐)

通过强制延迟让状态更新有时间被测试捕获,但这种方案依赖时间,稳定性差,不建议使用:

fun getExhibitions(loaderType: LoaderType) {
    viewModelScope.launch {
        state.update { it.loading(loaderType) } // #1 切换为加载状态

        delay(500) // 新增延迟代码

        val result = useCase.getExhibitions(
            params = GetExhibitionsUseCase.Params(shopId, sellerId)
        )

        when (result) {
            is UseCaseResult.Success -> {
                val displayModel = mapper.mapExhibitionList(result.value)
                state.update { it.loadingSuccess(displayModel.exhibitions) } // #2 切换为成功状态
            }
            is UseCaseResult.Fail -> {
                onErrorGetExhibitions(result.throwable)
            }
        }
    }
}

方案二:调整状态更新位置(推荐)

将加载状态的更新移出协程,直接在函数调用时同步执行。这样状态更新会立即被StateFlow分发,测试代码能稳定捕获到加载状态:

fun getExhibitions(loaderType: LoaderType) {
    state.update { it.loading(loaderType) } // 调整状态更新到协程外部
    viewModelScope.launch {
        val result = useCase.getExhibitions(
            params = GetExhibitionsUseCase.Params(shopId, sellerId)
        )

        when (result) {
            is UseCaseResult.Success -> {
                val displayModel = mapper.mapExhibitionList(result.value)
                state.update { it.loadingSuccess(displayModel.exhibitions) } // #2 切换为成功状态
            }
            is UseCaseResult.Fail -> {
                onErrorGetExhibitions(result.throwable)
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者Jayden

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 10:57:14