How to unit test code with Coroutines

Marcin Oziemski
ProAndroidDev
Published in
3 min readSep 2, 2019

--

Photo by Joyce McCown on Unsplash

In this article, I would like to focus on the topic of how to test code with coroutines. Let’s start with some example of ViewModel.

an example of ViewModel with coroutines

It’s a simple ViewModel that is fetching data from the server.

MyViewState represents all possible outcome of fetching data that will be visible to View via LiveData.

In getData() function we set the state to Loading and then in viewModelScope, we launch fetching data on Dispatchers.IO. After that, if nothing throws we set the state to Success with the data.

If something goes wrong we handle the exception and set sate to Error.

CoroutineContextProvider class is providing proper Dispatcher and we will use it to change / mock dispatchers in unit tests.

Before we start out unit tests we need to add one dependency.

testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:$versions.coroutinesVersion"

This package provides testing utilities for effectively testing coroutines, and was presented on Google I/O 2019 coroutine talk.

Now we can move to our tests.

InstantTaskExecutorRule is needed to test code with LiveData. Without it, we would get an error:

RuntimeException: Method getMainLooper in android.os.Looper not mocked.

TestCoroutineRule is my implementation of Rule that uses above coroutines-test package.

It sets the main dispatcher to testCoroutineDispatcher, runs the test then resets and cleanup. It also creates testCoroutineScope in which we can run our tests. If you don’t want to implement it yourself you can add it as a dependency from here.

We initialize MyViewModel with a mocked GetDataUseCase and TestContextProvider.

It changes all Dispatchers to Unconfined which executes initial continuation of the coroutine in the current call-frame and lets the coroutine resume in whatever thread that is used by the corresponding suspending function, without mandating any specific threading policy.

Each test starts with runBlockingTest from my test rule. Then the code is looking exactly the same as it would without using coroutines. We just call the function and check if proper results occur.

That’s the result of using Test Coroutine rule and Test Context Providers.

Those where the basis of testing coroutines, if you would like to know more advanced cases please check out coroutine test package site.

--

--