【问题标题】:Observe StateFlow emission in ViewModel initialization在 ViewModel 初始化中观察 StateFlow 发射
【发布时间】:2021-09-16 19:11:37
【问题描述】:

我有一个视图模型,它接收一个初始的 ViewState 对象,并有一个可公开访问的 state 变量,可以收集。

class MyViewModel<ViewState>(initialState: ViewState) : ViewModel() {
    val state: StateFlow<ViewState> = MutableStateFlow(initialState)
    val errorFlow: SharedFlow<String> = MutableSharedFlow()

    init {
        performNetworkCall()
    }

    private fun performNetworkCall() = viewModelScope.launch {
        Network.makeCall(
            "/someEndpoint",
            onSuccess = {
                (state as MutableStateFlow).tryEmit(<some new state>)
            },
            onError = {
                (errorFlow as MutableSharedFlow).tryEmit("network failure")
            }
        )
    }
}

从片段中观察此状态时,我可以看到初始状态(例如正在加载),并在网络调用成功完成时收集更改(例如,进入加载状态。)

但是,我不知道如何从我的ViewModelUnitTest 观察到这种发射。 我使用 kotlin 涡轮机来测试我的状态和共享流的排放,但我只能观察到在我调用 viewModel.state.testviewModel.errorFlow.test 之后发生的排放。

由于在 ViewModel 初始化之前我无法引用 viewModel.stateviewModel.errorFlow,我如何编写测试来验证我的初始化逻辑是否正确执行并根据 Network.makeCall 的模拟行为发出预期结果 -是state 的新发射还是errorFlow 发射?

【问题讨论】:

    标签: android kotlin kotlin-coroutines android-viewmodel kotlin-flow


    【解决方案1】:

    由于您的网络类在视图模型中没有任何引用,因此无法模拟/伪造 Network 类的行为。因此,为Network 创建一个引用。要捕获init 块中发生的事情,您可以在测试类中延迟初始化您的视图模型。在here 中将其描述为第二种方式。大致而言,您的类看起来类似于:

    class MyViewModel<ViewState>(
        initialState: ViewState,
        network: Network
    ) : ViewModel() {
        val state: StateFlow<ViewState> = MutableStateFlow(initialState)
        val errorFlow: SharedFlow<String> = MutableSharedFlow()
    
        init {
            performNetworkCall()
        }
    
        private fun performNetworkCall() = viewModelScope.launch {
            network.makeCall(
                "/someEndpoint",
                onSuccess = {
                    (state as MutableStateFlow).tryEmit(<some new state>)
                },
                onError = {
                    (errorFlow as MutableSharedFlow).tryEmit("network failure")
                }
            )
        }
    }
    

    @ExperimentalCoroutinesApi
    class MyViewModelTest {
    
        @get:Rule
        var coroutinesTestRule = CoroutinesTestRule()
    
        val viewModel by lazy { MyViewModel(/*pass arguments*/) }
    }
    

    CoroutineTestRule 可以在here 中找到。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      • 2015-06-11
      • 2021-12-19
      • 2018-01-03
      • 1970-01-01
      • 2012-10-19
      • 1970-01-01
      相关资源
      最近更新 更多