使用 LiveData、协程和事务测试 Android Room

2024-01-01

我想测试我的数据库层,但我陷入了第 22 条军规类型的情况。

测试用例由两部分组成:

  • 保存一些实体
  • 加载实体并断言数据库映射按预期工作

简而言之,问题在于:

  • Insert is a suspend方法,这意味着它需要运行在runBlocking{}
  • Query返回一个LiveData结果,这也是异步的。因此需要观察。有this https://stackoverflow.com/questions/44270688/unit-testing-room-and-livedataSO问题解释了如何做到这一点。
  • 但是,为了根据上面的链接观察 LiveData,我必须使用InstantTaskExecutorRule。 (否则我得到java.lang.IllegalStateException: Cannot invoke observeForever on a background thread.)
  • 这适用于大多数情况,但不适用于@Transaction- 带注释的 DAO 方法。测试永远不会结束。我认为等待某些事务线程时陷入僵局。
  • 删除InstantTaskExecutorRule让 Transaction-Insert 方法完成,但随后我无法断言其结果,因为我需要规则才能观察数据。

详细说明

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

测试用例是:

@RunWith(AndroidJUnit4::class)
class RoomTest {
    private lateinit var gameDao: GameDao
    private lateinit var db: AppDatabase

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    @Before
    fun createDb() {
        val context = ApplicationProvider.getApplicationContext<Context>()
        db = Room.inMemoryDatabaseBuilder(
            context, AppDatabase::class.java
        ).build()
        gameDao = db.gameDao()
    }

    @Test
    @Throws(Exception::class)
    fun storeAndReadGame() {
        val game = Game(...)

        runBlocking {
            gameDao.insert(game)
        }

        val allGames = gameDao.getAll()

        // the .getValueBlocking cannot be run on the background thread - needs the InstantTaskExecutorRule
        val result = allGames.getValueBlocking() ?: throw InvalidObjectException("null returned as games")

        // some assertions about the result here
    }

    @Test
    fun storeAndReadGameLinkedWithRound() {
        val game = Game(...)

        val rounds = listOf(
            Round(...),
            Round(...),
            Round(...)
        )

        runBlocking {
            // This is where the execution freezes when InstantTaskExecutorRule is used
            gameDao.insertGameAndRounds(game, rounds)
        }

        // retrieve the data, assert on it, etc
    }
}

The getValueBlocking是一个扩展函数LiveData,几乎是从上面的链接复制粘贴的

fun <T> LiveData<T>.getValueBlocking(): T? {
    var value: T? = null
    val latch = CountDownLatch(1)

    val observer = Observer<T> { t ->
        value = t
        latch.countDown()
    }

    observeForever(observer)

    latch.await(2, TimeUnit.SECONDS)
    return value
}

测试这个场景的正确方法是什么?我在开发数据库映射层时需要这些类型的测试,以确保一切按我的预期工作。


现在这个问题有一个解决方案,解释如下这个答案 https://stackoverflow.com/questions/56380210/android-instrumentation-test-doesnt-run-to-end-when-using-room-transaction-fun.

修复方法是向 Room 内存数据库生成器添加一行:

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

使用单线程执行器,测试可以按预期工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 LiveData、协程和事务测试 Android Room 的相关文章

随机推荐

  • PDOStatement 包含什么以及 fetch/fetchAll 有什么用?

    我无法理解 1 PDOStatement 对象内部有什么以及 2 为什么我需要 fetch 或 fetchAll 方法 我的数据库 一个名为 动物 的简单表 有 3 列 id 名称 物种 My code try pdo new PDO ds
  • Clang 格式换行符

    我正在寻找一个clang format设置以防止工具删除换行符 例如 我有我的ColumnLimit设置为 120 这是我重新格式化一些示例代码时发生的情况 Before include
  • 根据另一个数组的内容对 C 数组进行排序

    我正在尝试对数组进行排序A其元素是索引 索引引用另一个数组B其值将决定顺序A 所以 我想排序A这样B A i 在增加 例如 A 0 1 4 5 7 B 5 3 8 2 2 7 1 6 3 9 Sorted A将会 A 7 4 1 0 5 这
  • 如何修复Python缩进

    我有一些 Python 代码的缩进不一致 大量制表符和空格的混合使情况变得更糟 甚至空格缩进也没有保留 该代码按预期工作 但难以维护 我怎样才能修复缩进 比如HTML 整洁 https en wikipedia org wiki HTML
  • 如何在echarts中添加渐变颜色?

    I made a echart line graph https stackblitz com edit angular aqghec file src 2Fapp 2Fapp component ts Now I want to add
  • 自定义 UItableView 在 ios8 上无法正确显示

    我做了一个定制UITableViewCell当我显示它时 我得到了这个结果 我在 iPhone 5 上运行 xcode 6 和 iOS 8 beta 1 https i stack imgur com 9Oswn png https i s
  • 只读时无法使用文本框获取文本?

    我有一个文本框
  • CSS Line-Through 未被删除

    我有一些代码可以在 TR 上为已删除的行添加一条直通线 但这意味着我的 操作 列 只有 按钮会受到影响 这是因为按钮之间存在单独的空间 这些空间最终也会被贯穿 在浏览了 W3Schools 后 我很困惑为什么这个例子不起作用 table t
  • 如何设置 tkinter textvariable 在单独的线程上运行?

    尝试使用 main 函数变量更新在线程上运行的 tkinter textvariable 我实现了一个基于线程的解决方案 因此 tkinter 主循环后面的代码可以运行 https stackoverflow com a 1835036 1
  • 如何使用功能状态生成随机数?

    我正在努力弄清楚如何将 State 的函数表示与 Scala 的 Random 类合并以生成随机整数 我正在从书上学习Scala 中的函数式编程 所以大部分代码都是从那里获取的 以下是 State 类的样子 直接来自书中 case clas
  • 使用 NSIS 安装程序向注册表项授予权限的有效方法是什么?

    我正在尝试使用访问控制插件 http nsis sourceforge net AccessControl plug in在 NSIS 中设置注册表项的权限 它不起作用 安装程序运行后 所有用户组没有完全控制权 我在下面创建了一个示例 这里
  • Eclipse:有没有办法在组织导入中强制导入来解决歧义?

    我在 android 项目上使用 Eclipse 我更新到 Lion 问题开始出现 尝试了几个小时 没有结果 问题是这样的 我有几十个文件com stuff morestuff在我的项目中 我想 ctrl shift O 我的项目 这样每个
  • VS2010单元测试“待处理”且测试无法完成

    我正在使用 VS2010 Windows 7 每次我尝试运行单元测试时 它都会保持 待处理 状态并且测试无法完成 我试着遵循这个msdn说明 http msdn microsoft com en us library ms182532 28
  • Netflix 如何在不刷新页面且无需 JavaScript 的情况下提交评分?

    我正在尝试为我的网站做一些类似 Netflix 的 5 星级评级系统的事情 我注意到 Netflix 即使禁用了 JavaScript 仍然会在不刷新页面的情况下提交评级 这是显而易见的 因为当您手动重新加载页面时 您可以看到新的评级 但是
  • React-navigation 在调试模式下工作正常,但在发布模式下不行

    几周以来我遇到了一个问题 我在我的react native应用程序中使用react navigation 当我在调试模式下在我的设备上测试时 我在屏幕之间正确导航 但是当我构建签名的apk时 导航不再工作 我尝试了一切 但没有任何效果 我正
  • 在已知缺失时间间隔之间插入 3D 坐标

    数据是空间中的路径 我有 3D 位置数据 x y z 和记录位置点的时间 x y 和 z 坐标是物体在 3D 空间中移动的点位置 时间值是记录每个点的时间 从 0 开始 x y z time s 0 1 2 2 3 3 0 2 4 2 4
  • 为什么不在java中使用带有锁的try?

    我读了这个话题 https stackoverflow com questions 6965731 are locks autocloseable 和这个博客文章 http www java7developer com blog p 256
  • 编译时出现错误?

    当我编译代码时 我收到这些错误 我有 user include 下的所有标题 g Ip appmanager inc Icore inc p appmanager src appmanager process cpp o p appmana
  • 本地主机上的 404 错误

    我正在尝试使用一些ajax 来发送一些电子邮件 我在使用冷聚变之前已经这样做过并且没有任何问题 我遇到的是本地主机未在目录中找到明确的文件 事实上 该文件与index php 位于同一目录中 这没有发现任何问题 然而它给了我一个404错误找
  • 使用 LiveData、协程和事务测试 Android Room

    我想测试我的数据库层 但我陷入了第 22 条军规类型的情况 测试用例由两部分组成 保存一些实体 加载实体并断言数据库映射按预期工作 简而言之 问题在于 Insert is a suspend方法 这意味着它需要运行在runBlocking