LiveData testing: how to track the sequence of value changes?

Viewed 346

I study LiveData testing by official tutorial. I want to understand how I can verify the sequence of changing the value of LiveData in the test. I added code like this to the class under test (TasksViewModel):

val processing = MutableLiveData <Boolean> (false)

fun someLongProcessing () {
    processing.value = true
    viewModelScope.launch (Dispatchers.IO) {
        sleep (10000)
        processing.value = false
    }
}

I want to check that processing first evaluates to false and then to true. I added this code to the test:

    tasksViewModel.someLongProcessing ()
    var processing = tasksViewModel.processing.getOrAwaitValue ()
    assertTrue(processing)
    processing = tasksViewModel.processing.getOrAwaitValue()
    assertFalse(processing)

But the second call to getOrAwaitValue always returns true, although it expected to return the next LiveData value - false. getOrAwaitValue function code:

@VisibleForTesting (otherwise = VisibleForTesting.NONE)
fun <T> LiveData <T> .getOrAwaitValue (
        time: Long = 2,
        timeUnit: TimeUnit = TimeUnit.SECONDS,
        afterObserve: () -> Unit = {}
): T {
    var data: T? = null
    val latch = CountDownLatch (1)
    val observer = object: Observer <T> {
        override fun onChanged (o: T?) {
            data = o
            latch.countDown ()
            this@getOrAwaitValue.removeObserver (this)
        }
    }
    this.observeForever (observer)

    try {
        afterObserve.invoke ()

        // Don't wait indefinitely if the LiveData is not set.
        if (! latch.await (time, timeUnit)) {
            throw TimeoutException ("LiveData value was never set.")
        }

    } finally {
        this.removeObserver (observer)
    }

    @Suppress ("UNCHECKED_CAST")
    return data as T
}

What's wrong here? Maybe there is another way to test the sequence of changing LiveData values?

0 Answers
Related