lundi 27 janvier 2020

Testing Transaction queries of Room in `runBlockingTest`

How can I test Transaction database operation, insertItineraries for Room?

Error

java.lang.IllegalStateException: This job has not completed yet

at kotlinx.coroutines.JobSupport.getCompletionExceptionOrNull(JobSupport.kt:1188) at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest(TestBuilders.kt:53) at kotlinx.coroutines.test.TestBuildersKt.runBlockingTest$default(TestBuilders.kt:45) at com.andigeeky.skyscannertest.db.ItineraryDaoTest.test insert itineraries with legs(ItineraryDaoTest.kt:44) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

ItineraryDao

@Dao
@OpenForTesting
interface ItineraryDao {

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertLegEntities(legs: List<LegEntity>)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertItineraryEntities(itineraries: List<ItineraryEntity>)

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    suspend fun insertItineraryLeg(itineraryLegEntities: List<ItineraryLegEntity>)

    @Transaction
    suspend fun insertItineraries(
        itineraries: List<ItineraryEntity>,
        legs: List<LegEntity>,
        itineraryLegEntities: List<ItineraryLegEntity>
    ){
        insertItineraryEntities(itineraries)
        insertLegEntities(legs)
        insertItineraryLeg(itineraryLegEntities)
    }

    @Transaction
    @Query("SELECT * FROM ItineraryEntity")
    fun getItineraryWithLegs(): LiveData<List<ItineraryWithLegs>>
}

ItineraryDaoTest

@ExperimentalCoroutinesApi
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [Build.VERSION_CODES.P])
class ItineraryDaoTest : DbTest() {

    @get:Rule
    var instantTaskExecutorRule = InstantTaskExecutorRule()
    @Captor
    lateinit var captor: ArgumentCaptor<ArrayList<ItineraryWithLegs>>

    @Before
    fun setUp() {
        MockitoAnnotations.initMocks(this)
    }

    @Test
    fun `test insert itineraries with legs`() {
        runBlockingTest {
            val observer = mock<Observer<List<ItineraryWithLegs>>>()
            val legs = TestUtil.createLegs(1)
            val itineraries = TestUtil.createItineraries(1)
            val itineraryLegs = TestUtil.createItineraryLegEntities(1)

            skyScannerDatabase.itineraryDao().insertItineraries(itineraries, legs, itineraryLegs)
            skyScannerDatabase.itineraryDao().getItineraryWithLegs().observeForever(observer)

            captor.run {
                verify(observer, times(1)).onChanged(capture())
                assertEquals(itineraryLegs.size, value.size)
            }
        }
    }
}

DbTest

@UseExperimental(ExperimentalCoroutinesApi::class)
abstract class DbTest : CoroutineTestBase() {
    @Rule
    @JvmField
    val countingTaskExecutorRule = CountingTaskExecutorRule()
    lateinit var skyScannerDatabase: SkyScannerDatabase

    @Before
    fun initDb() {
        val app = ApplicationProvider.getApplicationContext<Context>()
        skyScannerDatabase = Room.inMemoryDatabaseBuilder(app, SkyScannerDatabase::class.java)
            .allowMainThreadQueries()
            .setTransactionExecutor(Executors.newSingleThreadExecutor())
            .build()
    }

    @After
    fun closeDb() {
        countingTaskExecutorRule.drainTasks(10, TimeUnit.SECONDS)
        skyScannerDatabase.close()
    }
}

Aucun commentaire:

Enregistrer un commentaire