当前位置: 首页 > 知识库问答 >
问题:

使用viewModelScope收集Kotlin Coroutine单元测试流

席成仁
2023-03-14

我想测试我的ViewModel的一个收集流的方法。在收集器内部,一个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扩展使用TestCoroutineDispatcher,还使用LiveData的即时执行器扩展:

    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)
    }
}

共有1个答案

单展
2023-03-14

你都可以试试,

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")
}
 类似资料:
  • 当将CoroutineScope注入到用于单元测试的ViewModel中时,是否也应该使用注入和定义CoroutineDispatcher,即使在生产代码中不需要它? 在此用例中,生产代码中不需要,因为在someRepository.kt中,reverfit处理上的线程,而返回上的数据,这两种情况都是默认的。 对保存在Kotlin流值中的Android的ViewModel视图状态值运行单元测试。

  • 单元测试 单元测试仅依赖于源代码,是测试代码逻辑是否符合预期的最简单方法。 运行所有的单元测试 make test 仅测试指定的package # 单个package make test WHAT=./pkg/api # 多个packages make test WHAT=./pkg/{api,kubelet} 或者,也可以直接用go test go test -v k8s.io/kubernet

  • 我正在Jenkins中设置一个CD管道,我想在两个不同的步骤中运行我的单元测试和集成测试。计划是让我的管道脚本看起来像这样,并让它们单独运行: 我已尝试使用surefire插件,如下所述:https://dzone.com/articles/splitting-unit-and-integration-tests-using-maven-a,而运行“mvn测试”只运行单元测试,但“mvn集成测试”

  • Android Studio 1.1 添加了单元测试支持,详细请看 Unit testing support。本章的其余部分描述的是 “instrumentation tests”。利用 Instrumentation 测试框架可以构建独立的测试 APK 并运行在真实设备(或模拟器)中进行测试。

  • 英文原文:http://emberjs.com/guides/testing/unit/ 单元测试用于测试代码的一个小片段,确保其功能正常。与集成测试不同,单元测试被限定在一个范围内,并且不需要Ember应用运行。 全局 vs 模块 过去如果没有作为一个全局变量加载整个Ember应用,要对应用进行测试非常困难。通过使用模块(CommonJS,AMD等)来编写应用,可以只加载被测试的部分,而不用将其