I want to test my database layer and I have caught myself in a catch-22 type of a situation.
The test case consists of two things:
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.