Testing Android Room with LiveData, Coroutines and Transactions

The problem is with the thing that transactions itself use runBlocking somewhere inside and that cause deadlock. I have changed InstantTaskExecutorRule to this class:

class IsMainExecutorRule : TestWatcher() {

    val defaultExecutor = DefaultTaskExecutor()

    override fun starting(description: Description?) {
        super.starting(description)
        ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() {
            override fun executeOnDiskIO(runnable: Runnable) {
                defaultExecutor.executeOnDiskIO(runnable)
            }

            override fun postToMainThread(runnable: Runnable) {
                defaultExecutor.executeOnDiskIO(runnable)
            }

            override fun isMainThread(): Boolean {
                return true
            }
        })
    }

    override fun finished(description: Description?) {
        super.finished(description)
        ArchTaskExecutor.getInstance().setDelegate(null)
    }
}

Then in code it will be:

@get:Rule
val liveDataRule = IsMainExecutorRule()

It will not cause deadlocks but still allow to observe livedatas.


There is now a solution to this issue, explained in this answer.

The fix is adding a single line to the Room in-memory database builder:

db = Room
    .inMemoryDatabaseBuilder(context, AppDatabase::class.java)
    .setTransactionExecutor(Executors.newSingleThreadExecutor()) // <-- this makes all the difference
    .build()

With the single thread executor the tests are working as expected.