【问题标题】:Android instrumentation test doesn't run to end when using Room @Transaction function使用 Room @Transaction 功能时,Android 仪器测试不会运行到结束
【发布时间】:2019-05-30 14:26:55
【问题描述】:

我正在使用 AS 3.4.1 和运行 Android 9 的模拟器进行测试。

当我在其中使用Room Dao Function annotated with @Transaction 时,以下测试不会运行。

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()
    }
}

这是插入函数:

@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
}

因此,如果我按原样运行测试(请参阅 BreakPoint #1),BreakPoint #2 甚至不会被调用,因此测试在之前的某个地方结束,没有结果。

如果我将 BreakPoint #1 处的代码替换为与 insert 函数完全相同的代码,则测试运行正常。

有人知道这里有什么问题吗?

【问题讨论】:

  • 那是因为你在运行阻塞没有完成的情况下断言
  • @Stavro Xhardha 我认为运行阻塞要等到身体完成?有什么办法解决这个问题?
  • 好吧,我真的不知道你的使用方式。但是请查看我在最后一节的帖子,我正在测试房间插入和选择。检查this
  • 我对这个相关问题的回答表明目前这是不可能的:(stackoverflow.com/questions/57027850/…

标签: android kotlin android-room android-architecture-components kotlin-coroutines


【解决方案1】:

您可以使用 setTransactionExecutor 在另一个线程中运行事务

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

然后在测试时使用 runBlocking 而不是 runBlockingTest

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

【讨论】:

  • 太棒了!对于 kotlinx.coroutines 1.6.0 的用户:也适用于 runTest
【解决方案2】:

我遇到了同样的问题,问题是因为InstantTaskExecutorRule,如果您删除下面的代码块,@Transaction 应该可以与suspend 关键字一起正常工作

@Rule
@JvmField
val instantTaskExecutorRule = InstantTaskExecutorRule()

这条规则似乎阻止了RoomDatabase 获取事务线程。在RoomDatabase.kt 中,执行在以下函数中被阻止:

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

希望这会有所帮助!

【讨论】:

  • 好吧,测试现在运行,但我需要liveDataValue() 方法的InstantTaskExecutorRule,因为删除此行后,会抛出错误:java.lang.IllegalStateException: Cannot invoke observeForever on a background thread
  • 你是如何使用 InstantTaskExecutorRule 的?
  • 测试运行,在删除 InstantTaskExecutorRule 后,但现在我的 observeForever 出现错误。
  • 我的.liveDataValue()扩展功能是这个的一个副本:github.com/googlesamples/android-architecture-components/blob/…
  • 有没有可能测试 LiveData + Coroutines?
猜你喜欢
  • 2014-05-22
  • 1970-01-01
  • 1970-01-01
  • 2017-12-10
  • 1970-01-01
  • 1970-01-01
  • 2017-04-01
  • 2018-03-25
  • 1970-01-01
相关资源
最近更新 更多