我在使用runTest
时遇到了奇怪的问题。我有一个简单的视图模型
class LoadingViewModel(
private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {
// more function in here
var xyz by mutableStateOf(false)
fun checkXyz() {
viewModelScope.launch {
delay(1000L)
xyz = true
}
}
}
正在加载视图模型测试
@OptIn(ExperimentalCoroutinesApi::class)
class LoadingViewModelTest {
private val subject by lazy {
spyk(LoadingViewModel(UnconfinedTestDispatcher()))
}
@Before
fun setUp() {
MockKAnnotations.init(this, relaxed = true)
}
@Test
fun `xyz - when method called then should assign value on xyz`() = runTest {
subject.checkXyz()
verify {
subject.xyz = true
}
}
}
我将junit4
与Kotlin1.8.10
一起使用
获取错误
Verification failed: call 1 of 1: LoadingViewModel(#3).setXyz(eq(true))) was not called.
Calls to same mock:
1) LoadingViewModel(#3).checkXyz()
2) LoadingViewModel(#3).getTag(androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY)
3) LoadingViewModel(#3).setTagIfAbsent(androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY, androidx.lifecycle.CloseableCoroutineScope@2d5580f6)
我检查,如果删除delay
,它工作正常。
更新
在viewModelScope
中添加ioDispatcher
后,我得到了与上述相同的错误
fun checkXyz() {
viewModelScope.launch(ioDispatcher) {
delay(1000L)
xyz = true
}
}
2条答案
按热度按时间icomxhvb1#
函数
checkXyz()
在测试中并没有真正实现您所期望的功能,所以要么是测试不正确,要么是checkXyz()
的实现不正确。checkXyz()
在后台异步赋值。这是因为它使用了viewModelScope.launch()
。因此,我们不应该期望在调用checkXyz()
后立即赋值。它可能在未来的某个地方发生,但我们不知道确切的时间。如果您的想法是在从
checkXyz()
返回之后已经赋值了,那么您应该使用suspend函数而不是viewModelScope.launch()
。那么您就无法轻松地测试其效果,因为您不知道异步操作何时完成。您必须从它返回一个Job
对象,才能在后台观察操作并等待它完成:但是,如果这个函数的“标准”用法是等待它完成,那么它应该是真正的suspend函数。
gj3fmq9x2#
您正在向ViewModel传递一个调度器,但实际上并没有在视图模型的代码中使用它,因此它使用了自己的调度器,而您的测试并不知道它。
使用分配给ViewModel的调度程序(测试中的测试调度程序)