繁体   English   中英

Android:测试室迁移

[英]Android: Testing room migration

我有一个迁移,我在其中添加了一个新列迁移定义为

val MIGRATION_20_21: Migration = object : Migration(20, 21) {
    override fun migrate(database: SupportSQLiteDatabase) {
        database.execSQL("ALTER TABLE tests ADD COLUMN deleted INTEGER NOT NULL DEFAULT 0")

    }
}

该领域被用作

@ColumnInfo(name = "deleted") var deleted: Boolean = false,

我有这个迁移的测试用例,看起来像

@Test
@Throws(IOException::class)
fun migrate20to21() {
    var db = helper.createDatabase(TEST_DB, 20).apply {
        
        addTestsToDatabase(this, true)
       
        close()
    }

    db = helper.runMigrationsAndValidate(TEST_DB, 21, true,
            MIGRATION_20_21)

    var cursor = db.query("SELECT * FROM tests WHERE id = ?", arrayOf("id0"))
    MatcherAssert.assertThat(cursor, Is(notNullValue()))
    MatcherAssert.assertThat(cursor.moveToFirst(), `is`(true))
    MatcherAssert.assertThat(cursor.getColumnIndex("deleted"), `is`(38))
    MatcherAssert.assertThat(cursor.getInt(cursor.getColumnIndex("deleted")), `is`(0))

我收到错误迁移没有正确处理:测试我看到预期和找到的表信息有所不同

Expected: deleted=Column{name='deleted', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='null'}, local_created_at=Column{name='local_created_at', type='INTEGER', affinity='3', notNull=false, primaryKeyPosition=0, defaultValue='null'}

Found: deleted=Column{name='deleted', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=0, defaultValue='0'}

为什么默认值存在差异以及当我将其定义为非空时它如何为空。

为什么默认值存在差异以及当我将其定义为非空时它如何为空

原因是“预期”是从实体派生的(在编译时),然后与正在/已经打开的实际数据库的架构(已经“找到”的内容)进行比较,因此您需要更改实体也有一个默认值 0,使用@ColumnInfo(defaultValue = "0")

如果没有,默认值将为空,即没有指定默认值。

  • @ColumnInfodefaultValue是在Room 2.2.0中引入的,直到那个版本 DEFAULT 子句(我相信)被忽略并且预期/发现冲突不会出现。

所以实体应该包含

@ColumnInfo(defaultValue = "0")
val deleted: Int = 0
  • 或者代替Int = 0Boolean = false

修正重新更新显示:-

@ColumnInfo(name = "deleted") var deleted: Boolean = false,

那么你需要使用:-

@ColumnInfo(name = "deleted", defaultValue = "0") var deleted: Boolean = false,

重新评论

谢谢你。 当我说var deleted: Boolean = false 时,是不是和说defaultValue 不一样?

对了就不一样了。

为 var/val 设置值会在实例化对象时未提供值时设置字段的值,并有效地为对象分配默认值。

虽然defaultValue = "0"表示列定义在表的列定义中包含DEFAULT 0

例如

 `deleted` INTEGER NOT NULL DEFAULT 0

没有你得到

 `deleted` INTEGER NOT NULL

这就是 Room EXPECTED(因为它没有defaultValue = )在你的情况下,根据你的 ALTER 列定义是 FOUND 与预期的不同(没有 DEFAULT 所以 Room 的解释是 defaultValue = null)。

在您的情况下, defaultValue = "0" 很重要,因为 0 (false) 将用作 ALTER 之前存在的行的列的值,而 null 可能会导致运行时问题。

使用var deleted: Boolean = false也可能很重要,因为如果在实例化对象时省略该值,它会提供默认值。

  • 也许获得 Room 期望的最好/最简单的方法是更改​​您的实体,然后编译(例如 Ctrl + F9),然后检查生成的 java (在 Android Studio 中的 Android 视图中很容易看到),然后找到该类被命名为每用_Impl后缀的@Database类,然后寻找createAllTables方法,其包括预期的表定义。

  • 例如

  • 在此处输入图片说明

另一项修正案

关于评论

迁移是否使用了room创建的json文件?

不,除非使用AutoMigration AutoMigration 在编译时构建迁移代码(我相信),因此它需要架构并需要 exportSchema = true 和底层 gradle 架构位置指令。

迁移实际上发生在运行时并且不需要(甚至无法访问已保存的模式,因为我认为它们未包含在 APK 中)。

我当前的版本是 24,但这个字段是在版本 21 中添加的。所以即使我添加了 default = 0,它也只会重新创建 24.json。 这个 20 到 21 的测试用例失败了,因为 21.json 没有默认值。

我怀疑这可能是由于不同版本的 Room。 2.2.0之前, defaultValue不是一个选项,因此在比较预期和发现时会被忽略。 请注意,此比较是在执行迁移后进行的(我相信所有迁移)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM