Reputation: 2524
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?
Upvotes: 10
Views: 2305
Reputation: 14229
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!
Upvotes: 6
Reputation: 744
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()
}
Upvotes: 27