gpt4 book ai didi

使用 viewModelScope 的 Kotlin 协程单元测试流程集合

转载 作者:行者123 更新时间:2023-12-02 09:24:01 27 4
gpt4 key购买 nike

我想测试 ViewModel 收集 Flow 的方法。在收集器内部,LiveData 对象发生了变化,我想最后检查一下。设置大致如下:

//Outside viewmodel
val f = flow { emit("Test") }.flowOn(Dispatchers.IO)

//Inside viewmodel
val liveData = MutableLiveData<String>()

fun action() {
viewModelScope.launch { privateAction() }
}

suspend fun privateAction() {
f.collect {
liveData.value = it
}
}

当我现在在单元测试中调用 action() 方法时,测试会在收集流之前完成。测试可能如下所示:

@Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.value, "Test")
}

我通过这个 Junit5 扩展以及 LiveData 的即时执行程序扩展使用 TestCoroutineDispatcher:

    class TestCoroutineDispatcherExtension : BeforeEachCallback, AfterEachCallback, ParameterResolver {
@SuppressLint("NewApi") // Only used in unit tests
override fun supportsParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Boolean {
return parameterContext?.parameter?.type === testDispatcher.javaClass
}

override fun resolveParameter(parameterContext: ParameterContext?, extensionContext: ExtensionContext?): Any {
return testDispatcher
}

private val testDispatcher = TestCoroutineDispatcher()

override fun beforeEach(context: ExtensionContext?) {
Dispatchers.setMain(testDispatcher)
}

override fun afterEach(context: ExtensionContext?) {
Dispatchers.resetMain()
testDispatcher.cleanupTestCoroutines()
}
}

class InstantExecutorExtension : BeforeEachCallback, AfterEachCallback {
override fun beforeEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance()
.setDelegate(object : TaskExecutor() {
override fun executeOnDiskIO(runnable: Runnable) = runnable.run()
override fun postToMainThread(runnable: Runnable) = runnable.run()
override fun isMainThread(): Boolean = true
})
}

override fun afterEach(context: ExtensionContext?) {
ArchTaskExecutor.getInstance().setDelegate(null)
}
}

最佳答案

你可以尝试一下,

fun action() = viewModelScope.launch { privateAction() }

suspend fun privateAction() {
f.collect {
liveData.value = it
}
}

@Test
fun example() = runBlockingTest {
viewModel.action().join()
assertEquals(viewModel.liveData.value, "Test")
}

fun action() {
viewModelScope.launch { privateAction()
}

suspend fun privateAction() {
f.collect {
liveData.value = it
}
}

@Test
fun example() = runBlockingTest {
viewModel.action()
viewModel.viewModelScope.coroutineContext[Job]!!.join()
assertEquals(viewModel.liveData.value, "Test")
}

你也可以试试这个,

suspend fun <T> LiveData<T>.awaitValue(): T? {
return suspendCoroutine { cont ->
val observer = object : Observer<T> {
override fun onChanged(t: T?) {
removeObserver(this)
cont.resume(t)
}
}
observeForever(observer)
}
}

@Test
fun example() = runBlockingTest {
viewModel.action()
assertEquals(viewModel.liveData.awaitValue(), "Test")
}

关于使用 viewModelScope 的 Kotlin 协程单元测试流程集合,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58115153/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com