问题
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?
回答1:
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()
}
回答2:
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 find 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 it gets block in the below function:
private suspend fun Executor.acquireTransactionThread(controlJob: Job): ContinuationInterceptor
Hope this helps!
来源:https://stackoverflow.com/questions/56380210/android-instrumentation-test-doesnt-run-to-end-when-using-room-transaction-fun