测试失败,因为结果
为空
。为什么runblocking{...}
不以阻塞的方式在ViewModel中运行launch
块?
我知道,如果将其转换为返回deferred
对象的async
方法,则可以通过调用await()
获取对象,或者可以返回job
并调用join()
。但是,我想通过将我的ViewModel方法保留为void
函数来实现这一点,有没有办法做到这一点呢?
// MyViewModel.kt
class MyViewModel(application: Application) : AndroidViewModel(application) {
val logic = Logic()
val myLiveData = MutableLiveData<Result>()
fun doSomething() {
viewModelScope.launch(MyDispatchers.Background) {
System.out.println("Calling work")
val result = logic.doWork()
System.out.println("Got result")
myLiveData.postValue(result)
System.out.println("Posted result")
}
}
private class Logic {
suspend fun doWork(): Result? {
return suspendCoroutine { cont ->
Network.getResultAsync(object : Callback<Result> {
override fun onSuccess(result: Result) {
cont.resume(result)
}
override fun onError(error: Throwable) {
cont.resumeWithException(error)
}
})
}
}
}
// MyViewModelTest.kt
@RunWith(RobolectricTestRunner::class)
class MyViewModelTest {
lateinit var viewModel: MyViewModel
@get:Rule
val rule: TestRule = InstantTaskExecutorRule()
@Before
fun init() {
viewModel = MyViewModel(ApplicationProvider.getApplicationContext())
}
@Test
fun testSomething() {
runBlocking {
System.out.println("Called doSomething")
viewModel.doSomething()
}
System.out.println("Getting result value")
val result = viewModel.myLiveData.value
System.out.println("Result value : $result")
assertNotNull(result) // Fails here
}
}
您需要做的是用给定的Dispatcher将coroutine的启动打包到一个块中。
var ui: CoroutineDispatcher = Dispatchers.Main
var io: CoroutineDispatcher = Dispatchers.IO
var background: CoroutineDispatcher = Dispatchers.Default
fun ViewModel.uiJob(block: suspend CoroutineScope.() -> Unit): Job {
return viewModelScope.launch(ui) {
block()
}
}
fun ViewModel.ioJob(block: suspend CoroutineScope.() -> Unit): Job {
return viewModelScope.launch(io) {
block()
}
}
fun ViewModel.backgroundJob(block: suspend CoroutineScope.() -> Unit): Job {
return viewModelScope.launch(background) {
block()
}
}
注意顶部的ui、io和背景。这里的一切都是顶级+扩展功能。
然后,在viewModel中,您可以像这样开始您的coroutine:
uiJob {
when (val result = fetchRubyContributorsUseCase.execute()) {
// ... handle result of suspend fun execute() here
}
@ExperimentalCoroutinesApi
private fun unconfinifyTestScope() {
ui = Dispatchers.Unconfined
io = Dispatchers.Unconfined
background = Dispatchers.Unconfined
}
现在我想对这个函数进行单元测试。我正在使用Mockk: 不幸的是,由于以下异常,此测试失败: 我尝试用替换,但测试似乎在无限循环中等待。 有人能帮我弄一下这个吗? 提前致谢
当将CoroutineScope注入到用于单元测试的ViewModel中时,是否也应该使用注入和定义CoroutineDispatcher,即使在生产代码中不需要它? 在此用例中,生产代码中不需要,因为在someRepository.kt中,reverfit处理上的线程,而返回上的数据,这两种情况都是默认的。 对保存在Kotlin流值中的Android的ViewModel视图状态值运行单元测试。
问题内容: 我有以前具有大量方法的类,因此我将此方法的工作细分为“辅助”方法。 这些辅助方法声明为强制执行封装- 但是我想对大型公共方法进行单元测试。是否也可以对辅助方法进行单元测试,好象其中的一个失败,而调用它的公共方法也会失败,这样我们就可以确定为什么失败了? 另外,为了使用模拟对象测试这些对象,我需要将其可见性从私有更改为受保护,这是否可取? 问题答案: 一种方法是省略测试并将其放在同一程序
Android Studio 1.1 添加了单元测试支持,详细请看 Unit testing support。本章的其余部分描述的是 “instrumentation tests”。利用 Instrumentation 测试框架可以构建独立的测试 APK 并运行在真实设备(或模拟器)中进行测试。
英文原文:http://emberjs.com/guides/testing/unit/ 单元测试用于测试代码的一个小片段,确保其功能正常。与集成测试不同,单元测试被限定在一个范围内,并且不需要Ember应用运行。 全局 vs 模块 过去如果没有作为一个全局变量加载整个Ember应用,要对应用进行测试非常困难。通过使用模块(CommonJS,AMD等)来编写应用,可以只加载被测试的部分,而不用将其
我在ViewModel中有一个函数有两个状态,第一个状态总是加载,第二个状态取决于api或db交互的结果。 这是函数 但是我找不到测试状态是否发生的方法,所以我修改了现有的扩展函数,以 若要在LiveData更改时将数据添加到列表中,并在该列表中存储状态,但它从不返回加载状态,因为它发生在observe启动之前。是否有方法测试的多个值?