runTest在AndroidKotlin中无法正常工作

qoefvg9y  于 2023-03-19  发布在  Kotlin
关注(0)|答案(2)|浏览(169)

我在使用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
     }
 }
icomxhvb

icomxhvb1#

函数checkXyz()在测试中并没有真正实现您所期望的功能,所以要么是测试不正确,要么是checkXyz()的实现不正确。
checkXyz()在后台异步赋值。这是因为它使用了viewModelScope.launch()。因此,我们不应该期望在调用checkXyz()后立即赋值。它可能在未来的某个地方发生,但我们不知道确切的时间。
如果您的想法是在从checkXyz()返回之后已经赋值了,那么您应该使用suspend函数而不是viewModelScope.launch()。那么您就无法轻松地测试其效果,因为您不知道异步操作何时完成。您必须从它返回一个Job对象,才能在后台观察操作并等待它完成:

runTest {
    subject.checkXyz().join()
    verify {
        subject.xyz = true
    }
}

fun checkXyz(): Job {
     return viewModelScope {
        delay(1000L)
        xyz = true
     }
 }

但是,如果这个函数的“标准”用法是等待它完成,那么它应该是真正的suspend函数。

gj3fmq9x

gj3fmq9x2#

您正在向ViewModel传递一个调度器,但实际上并没有在视图模型的代码中使用它,因此它使用了自己的调度器,而您的测试并不知道它。
使用分配给ViewModel的调度程序(测试中的测试调度程序)

viewModelScope.launch(ioDispatcher) { ... }

相关问题