使用 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 的相关文章

  • Android - 手机锁定时执行操作

    我想知道如何在手机锁定时执行某些操作 或继续侦听传感器或电池更换事件 当手机锁定时 它会停止监听传感器的变化 我尝试过使用唤醒锁 但它不起作用 也许我使用错误 任何帮助 将不胜感激 我建议为此使用服务 即使手机被锁定 它们也会在后台运行 这
  • 使用 Protractor 检查浏览器控制台中没有错误

    我正在使用 Protractor 来测试 AngularJS 我想检查在测试结束时是否没有发生未捕获的异常并打印到浏览器控制台 有没有一种简单的方法可以做到这一点 如果您将 Protractor 与 Jasmine 一起使用 请使用以下代码
  • 从 admob 独立 SDK 切换到 Google Play 服务 SDK 时,apk 大小会膨胀

    使用 Admob SDK 我的 apk 大小为 230Kb 当用 google play services SDK 替换 Admob SDK 时 它是 1 5MB 膨胀了 6 倍以上 我想完整的 Google Play 服务客户端 SDK
  • 在 Android 上检测已接听的拨出电话

    我知道这个问题已经被问过很多次了 但没有答案 但我仍然希望有人终于解决了这个问题 问题 我有一台运行 Android 2 3 的未 root 设备 我需要创建一项服务 打电话 等待呼叫被应答 接听电话后挂断电话 有超时 和其他许多人一样 我
  • android studio更新到3.0后任务执行失败

    当我更新 Android Studio 3 0 时 出现错误 unable to merge with dex 然后我添加了mutiDexEnabled true并且还添加了com android support multidex 1 0
  • Android 服务 START_STICKY START_NOT_STICKY

    我需要让我的服务始终在后台运行 并使用 startService 函数启动我的服务 无论应用程序的状态如何 我都不想重新启动服务 这是我的观察 START STICKY gt 如果应用程序启动 则服务正在重新启动 当应用程序关闭时 服务也会
  • 垂直翻转 Android Canvas

    有没有一种简单的方法可以在 Android 中翻转画布 我似乎找不到任何可以让我垂直翻转它的东西 这样 y 轴上的零就是手机屏幕的底部而不是顶部 如果解决方案不是特别快也没关系 因为我没有对画布进行任何计算密集的操作 提前致谢 Try ca
  • 通过 Intent 从文件管理器中选择文件

    我想做的 我想获取文件字符串形式的路径 我通过 Android 文件管理器选择该路径 我拥有的 Intent intent new Intent Intent ACTION GET CONTENT intent setType startA
  • Android物理引擎[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 在研究了 3D 游戏编程之后 很快就明白了为什么物理引擎非常有用 Android 支持哪些物理引擎并且可以在 Android 上使用 关于
  • 不同风格的模块文件

    我正在尝试在同一个应用程序中实现播放服务和华为服务 但希望能够按风格配置使用哪一个 每种风格都使用自己的 applicationIdSuffix 因此 对于每种不同的风格 华为插件都会失败 我无法编译 我的应用程序模块包含agconnect
  • 带有内容提供商的小部件;无法使用ReadPermission?

    所以我刚刚为我的应用程序实现了一个小部件 它通过我的数据库从数据库获取数据ContentProvider 我在清单中定义了自己的读 写权限 声明我使用它们 似乎没有什么区别 并在内容提供程序中要求它们
  • 如何将您的终端与 Android 模拟器连接

    我尝试导航到 android 工具文件夹并输入 adb shell 命令 但它似乎不起作用 我的终端似乎只能识别命令的 adb 部分 并给我一条错误消息 我究竟做错了什么 通过键入列出所有连接的设备adb devices 检查是否列出了任何
  • Android/三星 Galaxy S 模拟器

    有没有办法在三星银河模拟器或类似的东西上尝试我的项目 我的项目在 HTC Legend 上运行 但在该设备上崩溃了 我如何在 android eclipse 上设置三星 Galaxy s 我设置了 W800 854 2 2 AVD 但它可以
  • 无法在 Android Studio 中运行项目

    当我尝试在 Android Studio 中运行我的项目时 我收到以下错误消息 Execution failed for task CricHQ dexDebug gt com android ide common internal Log
  • Android Studio错误的含义:未注释的参数覆盖@NonNull参数

    我正在尝试 Android Studio 创建新项目并添加默认值后onSaveInstanceState方法创建 MyActivity 类 当我尝试将代码提交到 Git 时 我收到一个我不明白的奇怪错误 代码是这样的 我得到的错误是这样的
  • 调用属于Fragment的Activity的函数

    我正在与多个Fragments在 Android 下 我对如何从嵌入式应用程序发送和接收数据感到困惑 为了简单的解释 我有一个ListFragment and a MapFragment使用解释的方法here https stackover
  • 如何在 Android 的应用程序中使用 LDAP 身份验证?

    我想在我们的应用程序中添加 LDAP 身份验证 我在 Github 上搜索并找到了两个应用程序 但它们无法连接到服务器 通过ldap连接服务器的必要条件是什么 查看 UnboundID SDK 他们有一个适用于 Android 的套件 该应
  • iPhone 操作系统测试最佳实践

    不久前 iPhone 的开发还相当简单 只有几个操作系统版本 甚至更少的设备 然而现在 有 2 个主要操作系统版本和 5 种不同的设备需要考虑 作为一家即将发布多个应用程序的公司 测试已成为越来越重要的问题 测试所有组合的最佳方法是什么 我
  • 找不到与给定名称“@style/Theme.AppCompat.Light”匹配的资源

    我已经研究这个问题几个小时了 从 github 下载存储库后 任何 xml 文件中的唯一错误是 No resource found that matches the given name style Theme AppCompat Ligh
  • 在android中测量不规则多边形的面积

    我正在开发一个应用程序 在其中我在地图上绘制多边形 并且我使用的地图不是谷歌 它的Mapsforge开源离线地图库 我可以通过将地理点转换为像素点来轻松在地图上绘制多边形 但在这里我想发现是不规则的多边形 为此我做了很多尝试 但它让我失败了

随机推荐

  • 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