1

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
  • 1
    your call to loadActivationCode returns immediately because it is launched within the uiScope. You would have to join that job in order to wait for it to exit or launch it as a child of runBlocking (which requires changing how you've done things). I'd consider calling viewModelJob.join() inside your Test, before the assertion. Commented May 25, 2019 at 5:19

1 Answer 1

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..

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.