Android Developers
Published in

Android Developers

Illustration by Kiran Puri

Testing two consecutive LiveData emissions in Coroutines

The problem

We wanted to test two consecutive LiveData emissions (one of those executed in a coroutine) but it wasn’t possible since we used to inject Dispatchers.Unconfined that executed all coroutines immediately. Because of this, by the time we could assert the emissions in the unit test, the first LiveData emission was missed and we could only check the second emission. More details to follow:

Dribbble Shot details screen in Plaid

The solution

We used the new TestCoroutineDispatcher from the coroutines library (kotlinx.coroutines.test package) to be able to pause and resume the CoroutineDispatcher of the coroutine created by the ViewModel.

  1. Before the test starts, pause the dispatcher and check the fast result was emitted during ViewModel init.
  2. Resume the test Dispatcher that kicks off the coroutine of the processUiModel method in the ViewModel.
  3. Verify that the slow result was emitted.

An Alternative Approach

There are other approaches you could choose to solve this problem. We chose the one that we thought it was the best when we faced this issue since it did not require changing the application code.

And the Good Practices

To make your tests accurate, fast and reliable, you should:

Always inject Dispatchers!

We couldn’t have solved the problem if Dispatchers weren’t injected into the ViewModel allowing us to use a TestCoroutineDispatcher in tests.

Inject TestCoroutineDispatcher instead of Dispatchers.Unconfined

Inject an instance of TestCoroutineDispatcher to your classes and use the runBlockingTest method to run the coroutines that use that dispatcher synchronously in your tests. You can also use TestCoroutineDispatcher to be able to resume and pause Coroutines as you wish.

What about Dispatchers.Unconfined?

You can also inject Dispatchers.Unconfined for testing if you want to execute the code inside coroutines synchronously (kotlinx-coroutines currently uses it for tests). However, Unconfined gives you less flexibility than a TestCoroutineDispatcher: you cannot pause Unconfined and it’s limited to immediate dispatch.

Testing LiveData

For more best practices about testing LiveData, check out Jose Alcerreca’s post about this.



Articles on modern tools and resources to help you build experiences that people love, faster and easier, across every Android device.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store