使用LiveData、协同程序和事务测试Android Room
我想测试我的数据库层,我发现自己陷入了一种第22条军规的境地 测试用例由两部分组成:使用LiveData、协同程序和事务测试Android Room,android,testing,kotlin,android-room,kotlin-coroutines,Android,Testing,Kotlin,Android Room,Kotlin Coroutines,我想测试我的数据库层,我发现自己陷入了一种第22条军规的境地 测试用例由两部分组成: 保存一些实体 加载实体并断言数据库映射按预期工作 简而言之,问题在于: Insert是一个suspend方法,这意味着它需要在runBlocking{} Query返回结果的LiveData,该结果也是异步的。因此,需要加以观察。有一个问题可以解释如何做到这一点 但是,为了根据上面的链接观察LiveData,我必须使用InstantTaskExecutorRule。(否则我会得到java.lang.Ill
- 保存一些实体
- 加载实体并断言数据库映射按预期工作
是一个Insert
方法,这意味着它需要在suspend
runBlocking{}
返回结果的Query
,该结果也是异步的。因此,需要加以观察。有一个问题可以解释如何做到这一点LiveData
- 但是,为了根据上面的链接观察LiveData,我必须使用
。(否则我会得到InstantTaskExecutorRule
)java.lang.IllegalStateException:无法在后台线程上调用ObserveForver。
- 这适用于大多数情况,但不适用于带注释的DAO方法。测试永远不会结束。我认为它在等待某个事务线程时陷入僵局
- 删除
可以让事务插入方法完成,但是我无法断言其结果,因为我需要规则来观察数据InstantTaskExecutorRule
Dao
类如下所示:
@Dao
interface GameDao {
@Query("SELECT * FROM game")
fun getAll(): LiveData<List<Game>>
@Insert
suspend fun insert(game: Game): Long
@Insert
suspend fun insertRound(round: RoundRoom)
@Transaction
suspend fun insertGameAndRounds(game: Game, rounds: List<RoundRoom>) {
val gameId = insert(game)
rounds.onEach {
it.gameId = gameId
}
rounds.forEach {
insertRound(it)
}
}
测试此场景的正确方法是什么?在开发数据库映射层时,我需要这些类型的测试,以确保一切都如我所期望的那样工作 问题在于事务本身在内部某处使用runBlocking,这会导致死锁。 我已将InstantTaskExecutorRule更改为此类:
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)
}
}
然后在代码中,它将是:
@get:Rule
val liveDataRule = IsMainExecutorRule()
它不会导致死锁,但仍然允许观察LiveData。现在有了解决此问题的方法,如中所述 修复程序正在向内存库数据库生成器中的文件室添加一行:
db = Room
.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.setTransactionExecutor(Executors.newSingleThreadExecutor()) // <-- this makes all the difference
.build()
db=房间
.inMemoryDatabaseBuilder(上下文,AppDatabase::class.java)
.setTransactionExecutor(Executors.newSingleThreadExecutor())//这是使用实时数据和协同程序访问测试室的唯一方法。很快,谷歌将发布新的测试库来解决这些问题。听到这个消息很难过。您是否碰巧与他们表示将在何处解决此问题有关?这是用于测试实时数据的google示例代码。另一个此解决方案似乎解决了此问题,但没有解释其工作的确切原因,也没有说明它是否会影响其他与生命周期相关的测试(如LiveData)。如果没有缺点和副作用,那么为什么不是默认的测试方法呢?你能详细说明一下@vbevans94吗?
@get:Rule
val liveDataRule = IsMainExecutorRule()
db = Room
.inMemoryDatabaseBuilder(context, AppDatabase::class.java)
.setTransactionExecutor(Executors.newSingleThreadExecutor()) // <-- this makes all the difference
.build()