Hi guys, I am getting strange issue using `runTest...
# coroutines
k
Hi guys, I am getting strange issue using
runTest
. I have a simple viewModel
Copy code
class LoadingViewModel(
    private val ioDispatcher: CoroutineDispatcher,
) : ViewModel() {

    var xyz by mutableStateOf(false)
    fun checkXyz() {
        viewModelScope.launch {
            delay(1000L)
            xyz = true
        }
    }
}
more code in 🧵
Copy code
@OptIn(ExperimentalCoroutinesApi::class)
class LoadingViewModelTest {

    private val subject by lazy {
        spyk(LoadingViewModel(UnconfinedTestDispatcher()))
    }

@Before
    fun setUp() {
        MockKAnnotations.init(this, relaxed = true)
    }

    @Test
    fun `xyz - when method called then should assign value on xyz`() = runTest {

        subject.checkXyz()
        verify {
            <http://subject.xyz|subject.xyz> = true
        }
    }
}
I am using
junit4
with kotlin
1.8.10
Getting error
Copy code
Verification failed: call 1 of 1: LoadingViewModel(#3).setXyz(eq(true))) was not called.

Calls to same mock:
1) LoadingViewModel(#3).checkXyz()
2) LoadingViewModel(#3).getTag(androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY)
3) LoadingViewModel(#3).setTagIfAbsent(androidx.lifecycle.ViewModelCoroutineScope.JOB_KEY, androidx.lifecycle.CloseableCoroutineScope@2d5580f6)
I checked and If removed
delay
it working fine.
j
Well if you have a delay, you're not setting
xyz
immediately, so why do you think you can immediately verify that it has been set?
e
also the delay in
viewModelScope
doesn't use the
TestCoroutineScheduler
, so this isn't testable anyway
j
Even if it were using the test scheduler, the test doesn't wait for this delay (even virtually)
e
yep.
advanceTimeBy
can move virtual time to allow you to observe the post-delay effects, but not in this case because
viewModelScope
is totally separate
j
Yes, what I meant is that the test doesn't even attempt to do it, but yeah it wouldn't work anyway. Not only the subject doesn't pass the given test dispatcher to the
launch
internally, but also it's given a different test dispatcher than the one from the
runTest
call, so I don't think it would work even if
subject
used its
ioDispatcher
property in the
launch
.
k
Hi Joffrey
why do you think you can immediately verify that it has been set?
I am just testing the function and see in the document
delay
can we skip by using
runTest
.
I tried to use
ioDispatcher
inside my
viewModelScope
but still I am getting error.
Copy code
fun checkXyz() {
     viewModelScope.launch(ioDispatcher) {
        delay(1000L)
        xyz = true
     }
 }
what else I need to add in test?