Thr*_*ian 9 android unit-testing android-livedata kotlin-coroutines
我在 ViewModel 中有一个具有 2 个状态的函数,第一个状态始终为 LOADING,第二个状态取决于 api 或 db 交互的结果。
这是功能
fun getPostWithSuspend() {
myCoroutineScope.launch {
// Set current state to LOADING
_postStateWithSuspend.value = ViewState(LOADING)
val result = postsUseCase.getPosts()
// Check and assign result to UI
val resultViewState = if (result.status == SUCCESS) {
ViewState(SUCCESS, data = result.data?.get(0)?.title)
} else {
ViewState(ERROR, error = result.error)
}
_postStateWithSuspend.value = resultViewState
}
}
Run Code Online (Sandbox Code Playgroud)
没有错误,测试可以很好地检查 ERROR 或 SUCCESS 的最终结果
@Test
fun `Given DataResult Error returned from useCase, should result error`() =
testCoroutineRule.runBlockingTest {
// GIVEN
coEvery {
useCase.getPosts()
} returns DataResult.Error(Exception("Network error occurred."))
// WHEN
viewModel.getPostWithSuspend()
// THEN
val expected = viewModel.postStateWithSuspend.getOrAwaitMultipleValues(dataCount = 2)
// Truth.assertThat("Network error occurred.").isEqualTo(expected?.error?.message)
// Truth.assertThat(expected?.error).isInstanceOf(Exception::class.java)
coVerify(atMost = 1) { useCase.getPosts() }
}
Run Code Online (Sandbox Code Playgroud)
但是我找不到测试LOADING状态是否发生的方法,所以我将现有的扩展函数修改为
fun <T> LiveData<T>.getOrAwaitMultipleValues(
time: Long = 2,
dataCount: Int = 1,
timeUnit: TimeUnit = TimeUnit.SECONDS,
afterObserve: () -> Unit = {}
): List<T?> {
val data = mutableListOf<T?>()
val latch = CountDownLatch(dataCount)
val observer = object : Observer<T> {
override fun onChanged(o: T?) {
data.add(o)
latch.countDown()
this@getOrAwaitMultipleValues.removeObserver(this)
}
}
this.observeForever(observer)
afterObserve.invoke()
// Don't wait indefinitely if the LiveData is not set.
if (!latch.await(time, timeUnit)) {
this.removeObserver(observer)
throw TimeoutException("LiveData value was never set.")
}
@Suppress("UNCHECKED_CAST")
return data.toList()
}
Run Code Online (Sandbox Code Playgroud)
在 LiveData 更改时将数据添加到列表并将状态存储在该列表中,但它永远不会返回 LOADING 状态,因为它发生在观察开始之前。有没有办法测试多个值LiveData?
iam*_*sal 10
使用mockk,您可以捕获值并将其存储在列表中,然后按顺序检查值。
//create mockk object
val observer = mockk<Observer<AnyObject>>()
//create slot
val slot = slot<AnyObject>()
//create list to store values
val list = arrayListOf<AnyObject>()
//start observing
viewModel.postStateWithSuspend.observeForever(observer)
//capture value on every call
every { observer.onChanged(capture(slot)) } answers {
//store captured value
list.add(slot.captured)
}
viewModel.getPostWithSuspend()
//assert your values here
Run Code Online (Sandbox Code Playgroud)
我假设您正在使用mockk库
首先你需要创建观察者对象
val observer = mockk<Observer<ViewState<YourObject>>> { every { onChanged(any()) } just Runs }
Run Code Online (Sandbox Code Playgroud)
使用先前的观察者对象观察您的实时数据
viewModel.postStateWithSuspend.observeForever(observer)
Run Code Online (Sandbox Code Playgroud)
调用您的 getPostWithSuspend() 函数
viewModel.getPostWithSuspend()
Run Code Online (Sandbox Code Playgroud)
验证一下
verifySequence {
observer.onChanged(yourExpectedValue1)
observer.onChanged(yourExpectedValue2)
}
Run Code Online (Sandbox Code Playgroud)
inline fun <reified T > LiveData<T>.captureValues(): List<T?> {
val mockObserver = mockk<Observer<T>>()
val list = mutableListOf<T?>()
every { mockObserver.onChanged(captureNullable(list))} just runs
this.observeForever(mockObserver)
return list
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1769 次 |
| 最近记录: |