Testing Room and LiveData with Kotlin17 Nov 2017
The database is empty and when we tap “SHOW LOG” it is displaying “null”:
After adding the user, the UI is refreshed and the “SHOW LOG” is displaying our new user:
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.
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