我正在尝试在我的视图模型中测试一些代码。我正在尝试使用调度程序异步进行两个网络调用,但尚未弄清楚如何测试。这是我本质上想做的事情的简化示例,
// View Model Function
fun initialise() {
viewModelScope.launch(coroutineExceptionHandler) {
val accountDeferred = async(Dispatchers.IO) { accountModel.getAccounts() }
val contentDeferred = async(Dispatchers.IO) { contentModel.getContent() }
val account = accountDeferred.await()
val content = contentDeferred.await()
handleResult(account, content) // viewState is updated
}
}
// Unit Test
// Simplified
class Test {
@get:Rule
val coroutineRule = CoroutineTestRule(StandardTestDispatcher())
@Test
fun `This is the test`() {
runTest{
whenever(accountModel.getAccounts()).thenReturn(
Result.success( getAccountContent() , ReasonStatus.empty()))
whenever(contentModel.getContent()).thenReturn(
Result.success( getContent(), ReasonStatus.empty()))
// start view model
viewmodel = ViewModel(accountModel, contentModel)
runCurrent()
// In debugging mode, the variable viewState is set, before the two jobs in the viewmodel finish
val viewState = viewmodel.viewState.value
// check contents
assertNotEmpty(viewState.accounts)
// always fails since the network calls have not completed
}
}
}
有什么建议可以确保两个异步等待在 runTest 块中的其他代码首先以可靠的方式执行之前执行?
为了确保网络调用在单元测试中的断言之前完成,您可以使用 TestCoroutineScope 中的 advanceUntilIdle() 方法。
@ExperimentalCoroutinesApi
class ViewModelTest {
@get:Rule
val coroutineRule = CoroutineTestRule(StandardTestDispatcher())
private val accountModel: AccountModel = mock(AccountModel::class.java)
private val contentModel: ContentModel = mock(ContentModel::class.java)
private lateinit var viewModel: ViewModel
@Test
fun `This is the test`() = runTest {
whenever(accountModel.getAccounts()).thenReturn(Result.success(getAccountContent(), ReasonStatus.empty()))
whenever(contentModel.getContent()).thenReturn(Result.success(getContent(), ReasonStatus.empty()))
// Start view model
viewModel = ViewModel(accountModel, contentModel)
// This will run all pending tasks until they're idle
advanceUntilIdle()
// Now, viewState should be updated
val viewState = viewModel.viewState.value
// Check contents
assertNotNull(viewState?.accounts)
assertTrue(viewState?.accounts?.isNotEmpty() == true)
}
}