在我的ViewModel
中,我有一个onTextChanged
方法,该方法通过对EditText
的数据绑定来调用。在这里,我使用viewModelScope.launch{}
启动suspend
函数。在该功能中,我延迟了500ms。现在如何测试onTextChanged
方法?我尝试的所有操作始终会导致延迟完成之前的测试完成。我尝试使用runBlockingTest
,TestCoroutineDispatcher
和runBlocking
。
文本监视器:
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
searchJob = if (searchJob?.isActive == true) {
searchJob?.cancel()
viewModelScope.launch { search(s.toString()) }
} else {
viewModelScope.launch { search(s.toString()) }
}
}
搜索方法:
private suspend fun search(query: String) {
delay(500)
searchUseCase(SearchParams(query)).fold({
}, {
})
}
测试:
@Test
fun `Search is fired after 500ms when text is changed`() = runBlockingTest {
val viewModel = ViewModel(useCase)
viewModel.onTextChanged("test", 0, 0, 0)
//TODO assert time was 500ms or more
//This fails
coVerify(exactly = 1) { useCase.invoke(any()) }
}
答案 0 :(得分:0)
google 推荐的是,您应该以某种方式将 CoroutineDispatcher
注入您的视图模型,以便您可以在测试期间对其进行更改。
class MainViewModel(
private val dispatcher: CoroutineDispatcher = Dispatchers.Default
) : ViewModel() {
private var _userData: MutableLiveData<Any> = MutableLiveData<Any>()
val userData: LiveData<Any> = _userData
fun savedDelayed() = viewModelScope.launch {
delay(1000)
saveSessionData()
}
suspend fun saveSessionData() {
viewModelScope.launch(dispatcher) {
_userData.value = "some_user_data"
}
}
}
@ExperimentalCoroutinesApi
class MainViewModelTest {
private val testDispatcher = TestCoroutineDispatcher()
@ExperimentalCoroutinesApi
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
@get:Rule
var instantExecutorRule = InstantTaskExecutorRule()
@Test
fun testsSaveSessionData() = runBlockingTest {
val mainViewModel = MainViewModel(testDispatcher)
mainViewModel.savedDelayed()
testDispatcher.advanceUntilIdle()
val userData = mainViewModel.userData.value
assertEquals("some_user_data", userData)
}
}
从中等文章中粘贴的代码,并针对您的用例进行了修改。请阅读文章以获得进一步的解释: https://medium.com/swlh/unit-testing-with-kotlin-coroutines-the-android-way-19289838d257