单元测试使用ViewModelScope.launch延迟调用暂停函数的ViewModel方法

时间:2019-07-10 08:20:51

标签: android unit-testing kotlin-coroutines

在我的ViewModel中,我有一个onTextChanged方法,该方法通过对EditText的数据绑定来调用。在这里,我使用viewModelScope.launch{}启动suspend函数。在该功能中,我延迟了500ms。现在如何测试onTextChanged方法?我尝试的所有操作始终会导致延迟完成之前的测试完成。我尝试使用runBlockingTestTestCoroutineDispatcherrunBlocking

文本监视器:

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()) }
    }

1 个答案:

答案 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