Android 房间迁移测试失败,但没有任何改变

Posted

技术标签:

【中文标题】Android 房间迁移测试失败,但没有任何改变【英文标题】:Android Room Migration test fails, although nothing changed 【发布时间】:2020-09-15 16:58:04 【问题描述】:

我正在尝试测试 Room 迁移,但测试总是失败。模型甚至没有变化。我只增加了版本号,迁移为空——测试仍然失败。我不明白我做错了什么。

假设我们有一个实体EntityExample,有两列ab。主键由ab 组成,我们对两列都有索引。代码如下:

@Entity(primaryKeys = "a", "b", indices = @Index("a"), @Index("b"))
public class EntityExample 
    @NonNull public Long a;
    @NonNull public Long b;

此外,我们在版本 1 中的数据库:

@Database(version=1,entities=EntityExample.class)
public abstract class DBExample extends RoomDatabase 

在版本 2 中:

@Database(version=2,entities=EntityExample.class)
public abstract class DBExample extends RoomDatabase 

还有迁移:

public class MigrationExample 
    public final static Migration MIGRATION_1_2 = new Migration(1,2) 
        @Override
        public void migrate(@NonNull SupportSQLiteDatabase database) 

        
    ;

为了在测试中访问架构,在 build.gradle 中添加了:

android 
    sourceSets 
        // Adds exported schema location as test app assets.
        debug.assets.srcDirs += files("$projectDir/schemas".toString())
    

最后是测试:

@Config(sdk = Build.VERSION_CODES.O_MR1)
@RunWith(RobolectricTestRunner.class)
public class MigrationExampleTest 

    @Rule
    public MigrationTestHelper helper;

    public MigrationExampleTest() 
        helper = new MigrationTestHelper(InstrumentationRegistry.getInstrumentation(),
                DBExample.class.getCanonicalName(),
                new FrameworkSQLiteOpenHelperFactory());
    

    @Test
    public void migrationTest() throws IOException 

        SupportSQLiteDatabase dbV1 = helper.createDatabase("migration-test", 1);
        dbV1.close();

        DBExample dbV2 = Room.databaseBuilder(
                InstrumentationRegistry.getInstrumentation().getTargetContext(),
                DBExample.class,
                "migration-test")
                .addMigrations(MigrationExample.MIGRATION_1_2)
                .build();
        dbV2.getOpenHelper().getWritableDatabase();
        dbV2.close();
    


测试在dbV2.getOpenHelper().getWritableDatabase(); 行失败

java.lang.IllegalStateException: Migration didn't properly handle: EntityExample(....EntityExample).
 Expected:
TableInfoname='EntityExample', columns=a=Columnname='a', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null', b=Columnname='b', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=2, defaultValue='null', foreignKeys=[], indices=[Indexname='index_EntityExample_a', unique=false, columns=[a], Indexname='index_EntityExample_b', unique=false, columns=[b]]
 Found:
TableInfoname='EntityExample', columns=a=Columnname='a', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null', b=Columnname='b', type='INTEGER', affinity='3', notNull=true, primaryKeyPosition=1, defaultValue='null', foreignKeys=[], indices=null

如您所见(向右滚动测试输出时),找到的 TableInfo 中缺少 indices 部分。此外,bprimaryKeyPosition 在 1 和 2 之间有所不同。我不明白为什么,我不知道究竟是什么导致了测试失败,也不知道如何解决这。运行应用程序有效,不会引发异常。我检查了模式,除了更新的版本号(参见https://justpaste.it/68l2b 和https://justpaste.it/3r45p)之外,它们完全一样。但是,测试失败了!

【问题讨论】:

我也有同样的问题。使用 SQL 语句创建索引不起作用,因为它们没有显示在 TableInfo 中,所以我的迁移测试也总是失败。 【参考方案1】:

如果您还没有,可以查看这篇关于迁移测试的好文章:https://medium.com/androiddevelopers/testing-room-migrations-be93cdb0d975

然后,在您的迁移中,您必须实际迁移数据库,执行从 1 到 2 的 SQL,例如通过创建索引。

Room 处理迁移链接、结构完整性和测试,但不处理迁移本身。 在https://developer.android.com/training/data-storage/room/migrating-db-versions 文档中,他们会迁移他们的数据库,您也应该这样做。

【讨论】:

v1 和 v2 之间没有任何变化时如何迁移数据库? 从您的错误消息中可以看出,您在 EntityExample 的字段 a 和 b 上添加了索引,这就是区别。您需要创建 SQL 来创建这些索引。如果你只是想清除之前的数据结构,只需将版本回滚到1,卸载并重新安装应用程序,然后重新开始:) 我没有在 v2 中添加任何内容。抱歉,如果我说得不够清楚:EntityExample 中的任何内容在 v1 和 v2 之间都没有更改。索引在 v1 中已经存在。 所以有一个没有索引存储的数据库,需要删除。如果您正在处理示例和教程,只需卸载您的应用并在 v1 上重新安装。如果是生产,就按 creatibg 索引做房间想要的,可能是房间版本的变化。 存储的数据库已经有了索引。至少它应该有,因为EntityExample 没有改变。这不是让应用程序运行或任何生产应用程序 - 它是关于让测试成功。为此,甚至没有使用存储的数据库。仅使用模式。而且架构完全相同。

以上是关于Android 房间迁移测试失败,但没有任何改变的主要内容,如果未能解决你的问题,请参考以下文章

由于房间中的唯一约束,数据库迁移失败

迁移房间数据库时有没有办法使用迁移期间计算的变量?

Android安装失败 - 相同的包但签名不同

添加表格时房间迁移失败

生成 Android 房间迁移的最佳方法是啥?

Android房间迁移null错误