Testing Room and LiveData with Kotlin

In this post, I’ll show how to unit test Google’s Room persistence library with LiveData in Android project written in Kotlin. You can find the project’s code on my GitHub.

The app is just storing user’s name in our Room database. The View is observing LiveData retrieved from the database by the ViewModel.

The database is empty and when we tap “SHOW LOG” it is displaying “null”:

Room and LiveData testing first screenshot

After adding the user, the UI is refreshed and the “SHOW LOG” is displaying our new user:

Room and LiveData testing second screenshot

Lets take a closer look how this functionality is implemented. First we have our User object:

It contains a mutable field userName.

Then we have our UserDao class which is a Data Access Object:

It is a Java class. The reason for that is Android Studio is not yet (at the time of writing this blogpost) code highlighting and completion for Room SQL queries in Kotlin. There are 3 standard SQL methods (insert, delete and update) but also two more interesting: getUser() and getUserAsLiveData(). The latter is returning User object wrapped inside a LiveData. I’ll explain that later in this post.

Then we have our database:

It contains one entity (User) and one Dao (UserDao). The companion object is just a quick way to have an instance of our database as a singleton. In production, you probably should use some dependency injections framework (such as Dagger 2) to provide your database instances. The rest of the code is pretty straightforward.

Now, let’s switch to the unit testing part. First, we need to create our database for testing purposes. Let’s use an abstract class here for code reusability:

For testing purposes, we’re using Room’s inMemoryDatabaseBuilder. It will create a non-persistent instance of our database, which will be discarded after the test ends.

Then we create our UserDaoTest class by extending abstract DbTest class. Don’t forget to use the open modifier and annotate the class with @RunWith(AndroidJUnit4::class).

Testing inserting and deleting user is pretty straightforward:

Room’s “in memory” database allows main thread operations so we can just call appDatabase.userDao().user to retrieve the User object. The problem arises when we want to call getUserAsLiveData() method. This method returns LiveData object. Room calculates the value wrapped in LiveData lazily, only when there is an observer. Fortunately using Kotlin’s extension functions we can solve this problem in elegant way.

Let’s provide a LiveData extension that will observe the value stored in LiveData, blocks the thread and returns the value:

Now we can use that in our test case:

First we call val userWrappedInLiveData = appDatabase.userDao().userAsLiveData which returns LiveData object. Then we apply our extension function to get User object: val userFromDb = userWrappedInLiveData.getValueBlocking(). As we can see, all three tests are passing:

Tests results