我想测试我的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)
}
}
你都可以试试,
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等)来编写应用,可以只加载被测试的部分,而不用将其