In the last post, we learned about Writing The First Unit Test in our Android Project. Now it’s time to level up the things a little. This post’s title is “Android Unit Test Room Database”; we will focus on testing the room database this time.
I guess what you usually do is you write your database code, and then you check the database inspector manually to see whether your code is working or not. It works, but the method is prone to errors, and that is why we must write a unit test to check all our database functions.
Table of Contents
Creating a Simple Database
To unit test room database, we need the database. Let’s quickly create a straightforward database to test. You can also refer to this Android Room Tutorial to learn about the room database in detail.
Entity
As we discussed in the last post, we will be creating an application named “Spend Tracker” throughout this Android Test Tutorial Series. The below data class is our entity to store a Spend in the Room Database.
1 2 3 4 5 6 7 8 9 10 11 |
@Entity(tableName = "spends") data class Spend( val date: Date, val amount: Int, val description: String ) { @PrimaryKey(autoGenerate = true) var id: Long = 0 } |
As we are using a Date type here that is not supported by room; we need to make a TypeConverter as well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
class DateConverter { @TypeConverter fun fromTimestamp(value: Long?): Date? { return value?.let { Date(it) } } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time } } |
Dao
To perform database operations we need to create a Dao interface.
1 2 3 4 5 6 7 8 9 10 11 12 |
@Dao interface SpendDao { @Insert suspend fun addSpend(spend: Spend) @Query("SELECT * FROM spends ORDER BY date DESC LIMIT 20") suspend fun getLast20Spends(): List } |
Database
Finally let’s create our database.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@Database(entities = [Spend::class], version = 1) @TypeConverters(DateConverter::class) abstract class SpendsDatabase : RoomDatabase() { abstract fun getSpendDao(): SpendDao companion object { private const val DB_NAME = "Spends-Database.db" @Volatile private var instance: SpendsDatabase? = null private val LOCK = Any() operator fun invoke(context: Context) = instance ?: synchronized(LOCK) { instance ?: buildDatabase(context).also { instance = it } } private fun buildDatabase(context: Context) = Room.databaseBuilder( context.applicationContext, SpendsDatabase::class.java, DB_NAME ).fallbackToDestructiveMigration().build() } } |
Our database is created and now we can perform operations to this database. Now let’s test our database to make sure it is working as expected.
Android Unit Test Room Database
As we did in the last post, we will generate a test class. The process is very simple. Right click anywhere inside your class that you want to test. In this case it is SpendsDatabase.
Now from the options select Generate…Â
After selecting Generate, you need to select Test.
Now you will see another popup window, that contains options for your Test class, you do not need to change anything just hit ok.
When you hit ok, a new dialog will ask you to select the package for your test class; make sure you choose the androidTest package this time.
We are creating the Test class inside androidTest because we will test an Android-specific thing, and hence it is not a regular unit test, but it is Instrumented Unit Test. Running this test will also require an emulator or an actual device.
We can also convert this test to a Unit Test using Roboelectric, as Roboelectric can simulate an android environment using JVM only. But we will learn about this in a separate post. For now, let’s do the Instrumented Unit Test.
Creating Unit Test
You need to write the following code, inside the Test class that we just generated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
@RunWith(AndroidJUnit4::class) class SpendsDatabaseTest : TestCase() { private lateinit var spendsDao: SpendDao private lateinit var db: SpendsDatabase @Before public override fun setUp() { val context = ApplicationProvider.getApplicationContext() db = Room.inMemoryDatabaseBuilder( context, SpendsDatabase::class.java ).build() spendsDao = db.getSpendDao() } @After @Throws(IOException::class) fun closeDb() { db.close() } @Test fun writeAndReadSpend() = runBlocking { val spend = Spend(Date(), 100, "for Bread") spendsDao.addSpend(spend) val spends = spendsDao.getLast20Spends() assertThat(spends.contains(spend)).isTrue() } } |
This time you can see we are using @RunWith(AndroidJUnit4::class). Apart from the @Test functions, this time, we have the following as well.
@Before: Function marked with this annotation executes before each test.
@After: Function marked with this annotation executes after each test.
As you can see inside
@Before, we are creating the database to test, and inside
@After, we are closing the database.
Finally, inside the
@Test function, we first insert a spend to the database, and then we are getting the last 20 spends. If our code is correct and working fine, the 20 spends fetched should contain the spend that we just inserted. And we are asserting the same in the last line.
Now you can run the test.
As you can see our test passed. The same way you can right more test cases.
Challenge For You
Congrats! on completing this post. Now here is a challenge for you. In this post, we created a class DateConverter. It would be best to test the class’s functions. And your challenge is to write Unit Tests (Same as the last post).
You can comment below on your answers.
Android Unit Test Room Database Source Code
Finally if you need to source code of my project then you can get it from here.
So that is all for this post, friends. I hope now you can Unit Testing Room Database. In case you have any question regarding this post feel free to comment it below. And finally, make sure you SHARE this post with your friends. Thank You 🙂