简体   繁体   中英

Android instrumentation test doesn't run to end when using Room @Transaction function

I'm testing with AS 3.4.1 and Emulator running Android 9.

The following test won't run, when I use a Room Dao Function annotated with @Transaction in it.

class RecurrenceManagerTest : DatabaseTest() {

    @Rule
    @JvmField
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    var recurringEntryId: Long = -1

    @Before
    override fun setup() {
        super.setup() // only initialized the db

        val recurringEntry = RecurringEntry(
            recurrence = Recurrence(DATE.toEpochMilli(), Recurrence.DAILY)
        )

        recurringEntryId = runBlocking { db.recurringEntryDao().insert(recurringEntry) }

        val recurringBookEntry = BookEntry.create(
            title = TITLE,
            date = DATE,
            value = VALUE,
            isPaid = IS_PAID,
            notes = NOTES,
            entryType = ENTRY_TYPE,
            categoryId = CATEGORY_ID,
            contacts = CONTACTS,
            recurringEntryId = recurringEntryId
        )

        runBlocking {
            db.bookEntryDao().insert(recurringBookEntry) // BreakPoint #1
        }
    }

    @Test
    fun testInsertRecurrencesAndSchedule() { 
        var recurringEntry = runBlocking { db.recurringEntryDao().get(recurringEntryId) } // BreakPoint #2

        assertThat(recurringEntry, notNullValue())

        runBlocking { RecurrenceManager.insertRecurrencesAndSchedule(ApplicationProvider.getApplicationContext(), db, recurringEntry!!) }

        val bookEntries = db.bookEntryDao().getBookEntries().liveDataValue()
    }
}

This is the function for inserting:

@Transaction
suspend fun insert(bookEntry: BookEntry): Long {
    val id = insert(bookEntry.entity)
    bookEntry.embeddedContacts?.apply {
        forEach {
            it.id = 0
            it.bookEntryId = id
        }
    }?.let {
        insert(it)
    }

    return id
}

So if I'm running the test like it is (see BreakPoint #1), BreakPoint #2 won't even be called, so the test ends somewhere before, without a result.

If I'm replacing the code at BreakPoint #1 with exact the same code, the insert function has, the test runs correctly.

Does anyone have an idea what's the issue here?

You can use setTransactionExecutor to run transaction in another thread

return Room
       .inMemoryDatabaseBuilder(context, MyRoomDatabase::class.java)
       .setTransactionExecutor(Executors.newSingleThreadExecutor())
       .build()

then while testing use runBlocking instead of runBlockingTest

@Test
fun moveItem() = runBlocking {
    transactionFunction()
}

I faced the same issue and the problem was because of the InstantTaskExecutorRule , if you remove the below block of code the @Transaction should work fine with the suspend keyword

@Rule
@JvmField
val instantTaskExecutorRule = InstantTaskExecutorRule()

It seems that this rule blocks the RoomDatabase from acquiring the transaction thread. In RoomDatabase.kt execution gets blocked in the below function:

private suspend fun Executor.acquireTransactionThread(controlJob: Job): ContinuationInterceptor

Hope this helps!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM