Unit Testing Android’s Room Database | Erselan Khan
Today I will show you how we can write unit test cases for Room Database on Android. But before moving forward, I would like to ask you to please follow my medium to get the latest updates about Android and other tech-related topics. I have already covered the Room Database topic before, so if you want to check out that too then please visit this link below:
https://erselankhan.medium.com/room-database-android-jetpack-93d9a217c537

Let’s add the dependencies for Room Database and JUnit4:
def room_version = "2.3.0"
// Room database
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
kapt "androidx.room:room-compiler:$room_version"
// Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:2.3.0"
// Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.3'
// optional - Test helpers
testImplementation "androidx.room:room-testing:$room_version"
// Instrumented Unit Tests
androidTestImplementation "junit:junit:4.13.2"
androidTestImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:1.5.0"
androidTestImplementation "androidx.arch.core:core-testing:2.1.0"
androidTestImplementation "com.google.truth:truth:1.1.3"
First, we need to set up our Room Database class, Entity class, and Dao interface:
UserDatabase class:
import androidx.room.Databaseimport androidx.room.RoomDatabaseimport
com.systems.unittesting.entity.UserEntity
@Database(entities = [UserEntity::class], version = 1)
abstract class UserDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
}
UserEntity Class:
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class UserEntity(
var name: String,
var age: Int,
var emailAddress: String,
@PrimaryKey(autoGenerate = true) val Id: Int? = null
)
UserDao Interface:
import androidx.lifecycle.LiveData
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Update
import com.systems.unittesting.entity.UserEntity
@Dao
interface UserDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(userEntity: UserEntity)
@Delete
suspend fun delete(userEntity: UserEntity)
@Query("Select * from UserEntity")
fun getUsersList(): LiveData<List<UserEntity>>
@Update(onConflict = OnConflictStrategy.REPLACE)
suspend fun update(userEntity: UserEntity)
}
As we are testing the Android component so we need to write an Instrumental test for this, so create a UserTestDao.kt file inside in your androidTest package like below:

and paste the code inside your UserTestDao.kt file:
import android.content.Context
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import com.systems.unittesting.entity.UserEntity
import com.systems.unittesting.getOrAwaitValue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
@SmallTest
class UserTestDao {
// A JUnit Test Rule that swaps the background executor
// used by the Architecture Components with a different one
//which executes each task synchronously
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var userDatabase: UserDatabase
private lateinit var userDao: UserDao
// execute before every test case
@Before
fun setup() {
val context = ApplicationProvider.getApplicationContext<Context>()
userDatabase = Room.inMemoryDatabaseBuilder(context, UserDatabase::class.java)
.allowMainThreadQueries()
.build()
userDao = userDatabase.userDao()
}
// execute after every test case
@After
fun teardown() {
userDatabase.close()
}
/*
test case to insert user in room database
*/
@Test
fun insertUser() = runBlockingTest {
val userEntity = UserEntity("Erselan Khan", 26, "Some Random Email", 1)
userDao.insert(userEntity)
val users = userDao.getUsersList().getOrAwaitValue()
assertThat(users).contains(userEntity)
}
/*
test case to delete user in room database
*/
@Test
fun deleteUser() = runBlockingTest {
val userEntity = UserEntity("Erselan Khan", 26, "Some Random Email", 1)
userDao.insert(userEntity)
userDao.delete(userEntity)
val users = userDao.getUsersList().getOrAwaitValue()
assertThat(users).doesNotContain(userEntity)
}
/*
test case to insert and update user in room database
*/
@Test
fun updateUser() = runBlockingTest {
val userEntity = UserEntity("Erselan Khan", 26, "Some Random Email", 1)
userDao.insert(userEntity)
val newUser = userEntity.copy(name = "Some Name")
userDao.update(newUser)
val users = userDao.getUsersList().getOrAwaitValue()
assertThat(users).contains(newUser)
}
}
We are using some JUnit annotations like @Before, @After, @Test, and @get:Rule. Before annotation method is called before every test case and After annotation method is called after every test case, Test annotation methods are called for the test cases and Rule annotation is for to define some rules for every test case. If you want to read some more details about it then kindly check out this article https://erselankhan.medium.com/junit-annotations-android-f4983ca7d581
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
We are using InstantTaskExecutorRule(), A JUnit Test Rule that swaps the background executor used by the Architecture Components with a different one that executes each task synchronously.
// execute before every test case
@Before
fun setup() {
val context = ApplicationProvider.getApplicationContext<Context>()
userDatabase = Room.inMemoryDatabaseBuilder(context, UserDatabase::class.java)
.allowMainThreadQueries()
.build()
userDao = userDatabase.userDao()
}
// execute after every test case
@After
fun teardown() {
userDatabase.close()
}
We are initializing our UserDatabase and UserDao before each test case and also enabled allowMainThreadQueries() too and close our database after every test case by calling this userDatabase.close().
/*
test case to insert user in room database
*/
@Test
fun insertUser() = runBlockingTest {
val userEntity = UserEntity("Erselan Khan", 26, "Some Random Email", 1)
userDao.insert(userEntity)
val users = userDao.getUsersList().getOrAwaitValue()
assertThat(users).contains(userEntity)
}
We are also using the getOrAwaitValue() method to get the data from the LiveData object. You can get this extension method from here: https://github.com/arsalankhan994/unit-testing-step-by-step/blob/main/app/src/androidTest/java/com/erselan/unittesting/LiveDataUtilAndroidTest.kt

That’s it for now. I will cover more topics on Android in my upcoming articles.
In case you missed:
- https://erselankhan.medium.com/junit-annotations-android-f4983ca7d581
- https://erselankhan.medium.com/unit-testing-on-android-for-functions-methods-f526ceab078e
Show your love by sharing this article with your fellow developers.
(Again, the source for this demo is on https://github.com/arsalankhan994/unit-testing-step-by-step/tree/main/app/src/androidTest/java/com/erselan/unittesting. Follow me for more content about Android, Kotlin, and other technologies. If you have any questions, go ahead and ask me here or email me at arsalankhan994@gmail.com and I’ll do my best to respond.)