【发布时间】:2017-09-13 20:32:37
【问题描述】:
我正在尝试在 Realm 上对迁移进行单元测试。我的主要问题是:如何维护 RealmObject 的不同架构版本,以便能够创建旧对象的实例,进行迁移,然后根据新架构版本检查它是否正确?
我首先尝试保留不同的架构版本,但由于对象具有相同的名称,尽管位于不同的包中,但它无法编译。
【问题讨论】:
我正在尝试在 Realm 上对迁移进行单元测试。我的主要问题是:如何维护 RealmObject 的不同架构版本,以便能够创建旧对象的实例,进行迁移,然后根据新架构版本检查它是否正确?
我首先尝试保留不同的架构版本,但由于对象具有相同的名称,尽管位于不同的包中,但它无法编译。
【问题讨论】:
在 Realm,我们通过将旧的 Realm 文件存储为资产来测试迁移机制(参见 https://github.com/realm/realm-java/tree/master/realm/realm-library/src/androidTest/assets),然后在迁移测试后编写测试来检查结果(参见 https://github.com/realm/realm-java/blob/master/realm/realm-library/src/androidTest/java/io/realm/RealmMigrationTests.java)。
【讨论】:
在Realm source code 和this project 的帮助下,我想出了如何执行领域迁移单元测试。
一步一步,这是您构建测试的方式:
RealmConfiguration,如下所示:(1) 将您的项目的架构版本升级到最新版本 (2) 保持与上述领域实例相同的名称 (3) 添加将运行迁移的迁移代码。 RealmConfiguration 创建一个 Realm 实例。如果迁移成功运行,则不会抛出异常。您将成功地将您的代码从该状态迁移到当前应用程序的 Realm 架构版本。 假设您第一次开始构建应用时,您的应用之前在架构版本 0 上运行。现在,您使用的是架构版本 1,并进行了一些更改。您正在编写测试以查看是否可以从版本 0 成功迁移到版本 1。
在版本 0 上创建 Realm 数据库的 Realm 文件。我通常这样做是使用我的应用程序使用版本 0 时所做的 git commit 检查我的代码,运行我的应用程序以创建 Realm 数据库,然后using the bash script I mention in this post 我将我的领域文件复制到我的计算机文件系统。将此领域文件存储在您的应用项目中的 androidTest/assets 资产目录中。
将TestRealmConfigurationFactory 文件复制到您的项目中。这就是您将用于从androidTest/assets Realm 文件创建 Realm 实例的方法。
创建测试。这是我从我运行的迁移测试中制作的一些示例代码:
@RunWith(AndroidJUnit4::class)
open class MigrationTest {
@get:Rule open val configFactory = TestRealmConfigurationFactory()
@get:Rule open val thrown = ExpectedException.none()
private lateinit var context: Context
@Before
fun setup() {
context = InstrumentationRegistry.getInstrumentation().context
}
@Test(expected = RealmMigrationNeededException::class)
@Throws(Exception::class)
fun migrate_migrationNeededIsThrown() {
val REALM_NAME = "0.realm"
val realmConfig = RealmConfiguration.Builder()
.name(REALM_NAME)
.schemaVersion(0)
.build()
configFactory.copyRealmFromAssets(context, REALM_NAME, realmConfig)
// should fail because my code base realm models have changed *since* this 0.realm file.
// When you want to get a realm instance, it will take what realm objects are already in memory (mapped by the "name" property of the RealmConfiguration) and it will compare it to the models in the application. If they are different, a realm migration exception will be thrown. So, you need to make sure to add Realm migrations to your code at all times.
val realm = Realm.getInstance(realmConfig)
realm.close()
}
@Test fun migrate_migrateFrom0toLatest() {
val REALM_NAME = "0.realm"
val realmConfig = RealmConfiguration.Builder()
.name(REALM_NAME)
.schemaVersion(RealmInstanceManager.schemaVersion)
.migration { dynamicRealm, oldVersion, newVersion ->
val schema = dynamicRealm.schema
for (i in oldVersion until newVersion) {
RealmInstanceManager.migrations[i.toInt()].runMigration(schema)
}
}
.build()
configFactory.copyRealmFromAssets(context, REALM_NAME, realmConfig)
val realm = Realm.getInstance(realmConfig)
realm.close()
}
// convenient method to generate 1 realm file in app directory to be able to copy to assets directory for the next migration test when schema version changes.
@Test fun createFileForCurrentVersionToCopyToAssetsFile() {
val REALM_NAME = "${RealmInstanceManager.schemaVersion}.realm"
val realmConfig = RealmConfiguration.Builder()
.name(REALM_NAME)
.schemaVersion(RealmInstanceManager.schemaVersion)
.build()
Realm.deleteRealm(realmConfig)
val realm = Realm.getInstance(realmConfig)
realm.close()
}
}
作为参考,这里是我的 RealmInstanceManager 和我创建的其他配套文件,以使我的迁移隔离。
open class RealmInstanceManager(private val userManager: UserManager) {
companion object {
val migrations: List<RealmSchemaMigration> = listOf(
Migration1()
)
var schemaVersion: Long = 0L
get() = migrations.size.toLong()
}
}
我的Migration1班级:
class Migration1: RealmSchemaMigration {
override fun runMigration(schema: RealmSchema) {
schema.get(OwnerModel::class.java.simpleName)!!
.addField("avatar_url", String::class.java)
.setRequired("avatar_url", true)
.transform { it.set("avatar_url", "") }
}
}
最后,我的RealmSchemaMigration 界面:
interface RealmSchemaMigration {
fun runMigration(schema: RealmSchema)
}
我发现上述文件和接口配置是管理我的项目中的迁移文件以运行测试以及应用程序本身的好方法。
真的,你已经完成了。迁移测试在函数migrate_migrateFrom0toLatest() 中,我从架构版本0(名为“0.realm”)中获取我的领域文件资产,并将其迁移到我的代码库中的最新版本。 createFileForCurrentVersionToCopyToAssetsFile() 函数不是必需的,但我喜欢它,因为在我运行测试后,我可以将我设备上的这个新创建的 Realm 文件复制到我的资产目录中,以用于我运行的下一个迁移测试。然后必须执行我上面解释的 git checkout 方法要方便得多。
【讨论】: