How to test Coroutine with ViewModel in Kotlin?

不问归期 提交于 2021-02-05 09:16:10

问题


I could not test my method it feels it doesn't reach inside uiScope.launch block and I have posted my viewModel method which I am trying to test and fetchActivationCodeWithDuration is suspend function. and in the bottom is my test class

and I get this message

java.lang.AssertionError: 
    Expected :ActivationCode(code=111111, expires=2019-05-23T10:03:50.614Z, duration=815960) Actual   :null

protected val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

fun loadActivationCode() {
    uiScope.launch {
        progressMessageMutableData.postValue(true)
        when (val result = activationCodeRepository.fetchActivationCodeWithDuration()) {
            is Resource.Success<ActivationCode> -> {
                progressMessageMutableData.postValue(false)
                activationMutableData.postValue(result.data)
            }
            is Resource.Failure -> {
                progressMessageMutableData.postValue(false)
                errorMessageMutableData.postValue(result.message)
            }
        }
    }

suspend fun fetchActivationCodeWithDuration(): Resource<ActivationCode> {}

Here is my testing class

@ExperimentalCoroutinesApi
@RunWith(JUnit4::class)
class ActivationViewModelTest {
    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @UseExperimental(ObsoleteCoroutinesApi::class)
    private val mainThreadSurrogate = newSingleThreadContext("UI thread")
    private lateinit var viewModel: ActivationViewModel
    private lateinit var serverTimeFetcher: IServerTimeFetcher
    private lateinit var activationCodeRepository: ActivationRepositoryCode

    @Before
    fun setup() {
        viewModel = ActivationViewModel()
        Dispatchers.setMain(mainThreadSurrogate)
        activationCodeRepository = mock(ActivationRepositoryCode::class.java)
        viewModel.activationCodeRepository = activationCodeRepository
    }

    @After
    fun tearDown() {
        Dispatchers.resetMain() // reset main dispatcher to the original Main dispatcher
        mainThreadSurrogate.close()
    }

    @Test
    fun whenSuccessMenuLoad_loadActivationCode() {
        runBlockingTest {
            Mockito.`when`(activationCodeRepository.fetchActivationCodeWithDuration()).
              thenReturn(Resource.Success(ActivationCode(code = "111111", expires = "2019-05-23T10:03:50.614Z", duration = 815960L)))
            viewModel.loadActivationCode()
            val expected = ActivationCode(code = "111111", expires = "2019-05-23T10:03:50.614Z", duration = 815960L)
            val actual = viewModel.activationData.value
            Assert.assertEquals(expected, actual)
        }
    }
}

回答1:


Better approach is to pass coroutineDispatcher to viewModel, so you can pass test dispatcher in your tests. so you should have :

class ActivationViewModel(val dispatcher:CoroutineDispatcher){}

and in your test you can init viewModel like this :

val dispatcher=Dispatchers.Unconfined
val viewModelInTest=ActivationViewModel(dispatcher)

and problem will be resolved..



来源:https://stackoverflow.com/questions/56279264/how-to-test-coroutine-with-viewmodel-in-kotlin

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!