Search code examples
unit-testingkotlinlocalandroid-room

Testing Room in Android (Kotlin)


I'm trying to test a Room database in Android, written in Kotlin, locally; that is not on an emulator and without instrumented testing. As I understand it this is possible using the Roboelectric framework but I'm having some trouble with this :

  • How does one select the appropriate class for the RunWith(CLASS) decorator ?

    I understand AndroidJUnit4 is necessary for instrumented tests, given that this is a local test should I be using JUnit4 instead or some other derivative from RoboElectric.

  • How should I correctly determine the context ?

    Trying InstrumentationRegistry.getTargetContext() requires that I use InstrumentationRegistry which isn't available when testing locally or that test can not be imported when importing androidx.test.platform.app.InstrumentationRegistry or android.support.test.InstrumentationRegistry. Trying ApplicationProvider.getApplicationContext() claims the reference getApplicationContext can't be found. I'm also not sure where I should be importing either InstrumentationRegistry or ApplicationProvider from.

In general I'm finding it tricky to determine the appropriate libraries to use in Java; all the documentation appears very version specific and assumes you magically know where to import a given class from where often such a classes appear in more then one library. Then package imported through gradle also seems to be well related but does not explicitly match the package being imported. If you have any general tips on this I would be quite keen to hear it.

My code so far is as follows:

package com.manaikan.airvendor.AirTime

import android.content.Context
import android.arch.persistence.room.Room
import androidx.test.platform.app.InstrumentationRegistry
import com.manaikan.airvendor.airtime.AirVendorDatabase
import com.manaikan.airvendor.airtime.BundleQuery
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import java.io.IOException
// Roboelectric
import androidx.test.core.app.ApplicationProvider

@RunWith(JUnit4::class)
class BundleTest {

    private lateinit var queryset : ENTITYDao
    private lateinit var database : APPLICATIONDatabase

    @Before
    fun setup()
    {
        val context = ApplicationProvider.getApplicationContext<Context>()
        database = Room.inMemoryDatabaseBuilder(context, APPLICATIONDatabase::class.java)
            .allowMainThreadQueries()
            .build()
        queryset = database.bundleQuery()
    }

    @After
    @Throws(IOException::class)
    fun tearDown()
    {
        database.close()
    }

    @Test
    @Throws(Exception::class)
    fun review()
    {
    }
}

Solution

  • It seems to me you were almost there. The main thing to change is the runner, use: AndroidJUnit4, and maybe the version of the dependencies. Assuming your database and DAO are set up correctly, this should work (add import for your classes):

    package com.manaikan.airvendor.AirTime
    
    import android.content.Context
    import androidx.room.Room
    import androidx.test.core.app.ApplicationProvider
    import androidx.test.ext.junit.runners.AndroidJUnit4
    import org.junit.After
    import org.junit.Before
    import org.junit.Test
    import org.junit.runner.RunWith
    import java.io.IOException
    
    @RunWith(AndroidJUnit4::class)
    class BundleTest {
    
      private lateinit var queryset : ChannelProgramsDao
      private lateinit var database : ChannelProgramsDatabase
    
      @Before
      fun setup()
      {
        val context = ApplicationProvider.getApplicationContext<Context>()
        database = Room.inMemoryDatabaseBuilder(context, APPLICATIONDatabase::class.java)
            .allowMainThreadQueries()
            .build()
        queryset = database.bundleQuery()
      }
    
      @After
      @Throws(IOException::class)
      fun tearDown()
      {
        database.close()
      }
    
      @Test
      @Throws(Exception::class)
      fun review()
      {
      }
    }
    

    It worked for me with the following dependencies:

      testImplementation "org.robolectric:robolectric:4.2"
      testImplementation "androidx.test.ext:junit:4.12"
    
      implementation "androidx.room:room-runtime:2.2.2"
      implementation "androidx.room:room-ktx:2.2.2"
      kapt "androidx.room:room-compiler:2.2.2"
      testImplementation "androidx.room:room-testing:2.2.2"