You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Room 2.3.0迁移测试触发onPreMigrate AbstractMethodError问题

问题根因

你遇到的AbstractMethodError是Room 2.3.0版本的已知问题,该版本的room-testing组件内的MigrationTestHelper.MigratingDelegate没有实现同一版本Room核心库新增的onPreMigrate抽象方法,该bug在2.4.0及以上版本已官方修复。

依赖配置问题解答

官方给出的依赖配置没有错误,但是对应不同测试场景:

  • testImplementation引入的依赖仅用于纯JVM环境的本地单元测试
  • Room迁移测试属于必须运行在Android设备/模拟器上的instrumented测试,因此必须将room-testing的依赖声明改为androidTestImplementation "androidx.room:room-testing:$room_version",你的判断是正确的。
完整可运行的Room迁移测试示例

第一步:依赖配置

建议优先将Room版本升级到2.4.0及以上,避免上述bug,build.gradle配置如下:

def room_version = "2.4.3"
// 生产环境依赖
implementation "androidx.room:room-runtime:$room_version"
// Java环境用annotationProcessor,Kotlin环境用kapt
kapt "androidx.room:room-compiler:$room_version"
// 迁移测试依赖,必须用androidTestImplementation
androidTestImplementation "androidx.room:room-testing:$room_version"
// 设备端测试基础依赖
androidTestImplementation "androidx.test.ext:junit:1.1.5"
androidTestImplementation "androidx.test:runner:1.5.2"

如果必须使用2.3.0版本,可参考文末的临时兼容方案。

第二步:编写迁移逻辑

// 1升2的迁移逻辑,根据你的业务修改SQL语句
val MIGRATION_1_2 = object : Migration(1, 2) {
    override fun migrate(database: SupportSQLiteDatabase) {
        // 示例:给user表新增age、address两列
        database.execSQL("ALTER TABLE user ADD COLUMN age INTEGER NOT NULL DEFAULT 0")
        database.execSQL("ALTER TABLE user ADD COLUMN address TEXT")
    }
}
// 将迁移逻辑添加到数据库构建配置中
Room.databaseBuilder(context, AppDatabase::class.java, "app_db")
    .addMigrations(MIGRATION_1_2)
    .build()

第三步:编写迁移测试类

测试类必须放在src/androidTest/java/你的应用包名目录下:

@RunWith(AndroidJUnit4::class)
class RoomMigrationTest {
    private val TEST_DB = "migration_test_db"

    // 注册MigrationTestHelper规则
    @get:Rule
    val helper = MigrationTestHelper(
        InstrumentationRegistry.getInstrumentation(),
        AppDatabase::class.java.canonicalName,
        FrameworkSQLiteOpenHelperFactory()
    )

    @Test
    fun testMigration1To2() {
        // 1、创建版本1的数据库,插入测试数据
        helper.createDatabase(TEST_DB, 1).apply {
            execSQL("INSERT INTO user (id, name) VALUES (1, '测试用户')")
            close()
        }
        // 2、执行迁移并自动验证表结构是否符合版本2的Entity定义
        val db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2)
        // 3、可选:验证迁移后数据完整性
        val cursor = db.query("SELECT id, name, age, address FROM user WHERE id = 1")
        assert(cursor.moveToFirst())
        assert(cursor.getInt(cursor.getColumnIndexOrThrow("age")) == 0)
        assert(cursor.getString(cursor.getColumnIndexOrThrow("address")) == null)
        cursor.close()
        db.close()
    }
}

2.3.0版本临时兼容方案

如果无法升级Room版本,可在androidTest目录下添加如下补丁类,替换测试中使用的MigrationTestHelper即可:

class FixedMigrationTestHelper(
    instrumentation: Instrumentation,
    dbClassName: String?,
    openFactory: SupportSQLiteOpenHelper.Factory
) : MigrationTestHelper(instrumentation, dbClassName, openFactory) {
    override fun createDatabase(name: String, version: Int): SupportSQLiteDatabase {
        val db = super.createDatabase(name, version)
        val delegateField = RoomOpenHelper::class.java.getDeclaredField("delegate")
        delegateField.isAccessible = true
        val originDelegate = delegateField.get(helper) as RoomOpenHelper.Delegate
        val proxyDelegate = Proxy.newProxyInstance(
            originDelegate.javaClass.classLoader,
            arrayOf(RoomOpenHelper.Delegate::class.java)
        ) { _, method, args ->
            if (method.name == "onPreMigrate") return@newProxyInstance Unit
            method.invoke(originDelegate, *args.orEmpty())
        }
        delegateField.set(helper, proxyDelegate)
        return db
    }
}

内容的提问来源于stack exchange,提问作者Suau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:39:03