观察 ViewModel 初始化中的 StateFlow 发射

dev*_*ry3 6 android kotlin android-viewmodel kotlin-coroutines kotlin-flow

我有一个视图模型,它接受初始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")
            }
        )
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

小智 1

由于您的网络类在视图模型中没有任何引用,因此不可能模拟/伪造Network类的行为。因此,创建一个参考Network。要捕获块中发生的情况init,您可以在测试类中延迟初始化视图模型。这里描述的是第二种方式。粗略地说,您的课程类似于:

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")
            }
        )
    }
}
Run Code Online (Sandbox Code Playgroud)
@ExperimentalCoroutinesApi
class MyViewModelTest {

    @get:Rule
    var coroutinesTestRule = CoroutinesTestRule()

    val viewModel by lazy { MyViewModel(/*pass arguments*/) }
}
Run Code Online (Sandbox Code Playgroud)

CoroutineTestRule可以在这里找到。