我有一个视图模型类,它使用使用 StateIn 运算符创建的 StateFlow。
I.E.
private val _state = MutableStateFlow(MyState())
private val myItems = myRepository.myFlow.stateIn(
viewModelScope, SharingStarted.WhileSubscribed(), emptyList<MyObject>())
val state: StateFlow<MyState> = combine(_state, myItems ) { state, myItems ->
..///
}.stateIn(viewModelScope, SharingStarted.WhileSubscribed(5000), MyState())
在阅读文档以及各种文章和SO问题(已过时)时,我发现您应该使用以下方法来测试它:
backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
//Collect your flow
}
我遇到的问题是,当我创建单元测试来测试我的视图模型时,状态的收集对于发生的断言来说不够快。
@Test
fun checkMyItemTest() = runTest {
val results = mutableListOf<MyState>()
val job = backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.state.collect {
results.add(it)
}
}
viewModel.onEvent(MyEvent.DoSomething())
assert(results[0].myStateParameter) //Perform some check on results[0]
assert(results[1].myStateParameter) //Perform some check on results[1]
job.cancel()
}
上面的测试在第二个断言中失败,因为 results 中只有一个元素。 我通过在两个断言调用之间插入 50 毫秒的
Thread.sleep
调用来使其工作,但这对我来说似乎不是最好的方法。
@Test
fun checkMyItemTest() = runTest {
val results = mutableListOf<MyState>()
val job = backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.state.collect {
results.add(it)
}
}
viewModel.onEvent(MyEvent.DoSomething())
assert(results[0].myStateParameter) //Perform some check on results[0]
Thread.sleep(50) /// <---- THIS
assert(results[1].myStateParameter) //Perform some check on results[1]
job.cancel()
}
我目前对使用 Turbine 不感兴趣
所以我希望了解如何正确测试我的流程以及如何收集它发出的值。
我也是测试新手,但从我读过的内容来看,
runTest{}
跳过了延迟,与 runBlocking 没有太大区别,所以这可能有效:
@Test
fun checkMyItemTest() = runTest {
val results = Channel<MyState>() // this is a rendevous channel
val job = backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
viewModel.state.collect {
results.send(it)
}
}
viewModel.onEvent(MyEvent.DoSomething())
val result1 = channel.receive() //suspends till it has a corresponding send call
val result2 = channel.receive()
assert(result1.myStateParameter) //Perform some check on result1
assert(result2.myStateParameter) //Perform some check on result2
}
我还没有运行代码。
您应该使用 StandardTestDispatcher 代替 UnconfinedTestDispathcher
@Test
fun checkMyItemTest() = runTest {
val results = mutableListOf<MyState>()
val job = backgroundScope.launch(StandardTestDispatcher(testScheduler)) {
viewModel.state.collect {
results.add(it)
}
}
viewModel.onEvent(MyEvent.DoSomething())
advanceUntilIdle()
assert(results[0].myStateParameter) //Perform some check on results[0]
assert(results[1].myStateParameter) //Perform some check on results[1]
job.cancel()
}
来自文档
记住 UnconfinedTestDispatcher 会急切地启动新的协程, 但这并不意味着它会急切地运行它们以完成 出色地。如果新协程挂起,其他协程将恢复 正在执行。
在本例中是视图模型状态的集合。它将收集默认的 StateFlow 值并放入您的
results
然后,当您发出新值时,协程不会等待该值,而是立即断言
result[1]
。