在之前的一篇文章中,我们介绍了一下构件组件,其中就提到了使用 Room 来进行数据库操作。但我们也有注意到,如果您错误地实施迁移,最严重的结果可能会导致您的应用崩溃或丢失用户数据。
除此之外,Migration.migrate 在编译时不会检查在方法中执行的 SQL 语句,这导致了更多的问题。了解到这个情况之后,对迁移进行测试就成了一项必做任务。 Room 提供了 MigrationTestHelper 测试工具,这一工具允许您:
在给定的版本中创建一个数据库
在数据库上运行一组给定的迁移
验证数据库 schema
当然,Room 不会验证数据库中的数据本身。这是您需要亲自去实现的东西。
以下是您需要了解的有关 Room 迁移测试的内容。
工作原理
为了进行迁移测试,Room 需要知道您当前数据库版本的几个要素:版本号、Entity、Identity Hash,以及为创建和更新 room_master_table 而做出的查询请求。所有这些都由 Room 在编译时自动生成,并存储在schema JSON 文件中。
在 build.gradle 文件中指定一个文件夹,来放置这些生成的 schema JSON 文件。在更新 schema 时,最终会出现一些 JSON 文件,每个版本都将有一个对应的文件。确保将每个生成的文件提交给源代码管理工具。下次再次增加版本号码时,Room 可以使用 JSON 文件进行测试。
先决条件
要生成 JSON 文件,请使用以下内容更新 build.gradle 文件:
1. 定义 schema 位置
defaultConfig {
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation":
"$projectDir/schemas".toString()]
}
}
}
2. 将 schema 位置添加到源码目录
android {
sourceSets {
androidTest.assets.srcDirs +=
files("$projectDir/schemas".toString())
}
3. 将 Room 测试库添加到依赖列表中
dependencies {
androidTestImplementation
“android.arch.persistence.room:testing:1.0.0-alpha5”
}
迁移测试规则
创建数据库和 schema,打开和关闭数据库,运行迁移 —— 您几乎需要为每个测试编写大量这样的样板代码。为了避免过度重复劳动,请在迁移测试类中使用 MigrationTestHelper 测试工具。
为了创建数据库以及验证迁移,MigrationTestHelper 很大程度上依赖于生成的 JSON 文件。
@Rule
public MigrationTestHelper testHelper =
new MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
<your_database_class>.class.getCanonicalName(),
new FrameworkSQLiteOpenHelperFactory());
您可以在特定版本中创建数据库:
// Create the database with version 2
SupportSQLiteDatabase db =
testHelper.createDatabase(TEST_DB_NAME, 2);
您可以运行一组迁移,并自动验证 schema 是否更新无误:
db = testHelper.runMigrationsAndValidate(TEST_DB_NAME, 4, validateDroppedTables, MIGRATION_1_2, MIGRATION_2_3, MIGRATION_3_4);
实施测试
测试策略很简单:
在特定版本中打开数据库;
插入一些数据;
运行迁移并验证 schema;
检查数据库中是否有正确的数据。
例如,数据库的版本 3 添加了一个新列:date 。因此,当测试从版本 2 到版本 3 的迁移时,我们检查插入到版本 2 的数据的有效性,也是我们新列的默认值。我们的 AndroidJUnitTest 看起来是这样的:
@Test
public void migrationFrom2To3_containsCorrectData() throws
IOException {
// Create the database in version 2
SupportSQLiteDatabase db =
testHelper.createDatabase(TEST_DB_NAME, 2);
// Insert some data
insertUser(USER.getId(), USER.getUserName(), db);
//Prepare for the next version
db.close();
// Re-open the database with version 3 and provide MIGRATION_1_2
// and MIGRATION_2_3 as the migration process.
testHelper.runMigrationsAndValidate(TEST_DB_NAME, 3,
validateDroppedTables, MIGRATION_1_2, MIGRATION_2_3);
// MigrationTestHelper automatically verifies the schema
//changes, but not the data validity
// Validate that the data was migrated properly.
User dbUser = getMigratedRoomDatabase().userDao().getUser();
assertEquals(dbUser.getId(), USER.getId());
assertEquals(dbUser.getUserName(), USER.getUserName());
// The date was missing in version 2, so it should be null in
//version 3
assertEquals(dbUser.getDate(), null);
}
测试从 SQLiteDatabase 到 Room 的迁移
从标准 SQLiteDatabase 到 Room 的步骤虽然乍一看很直观,但我们觉得有必要详细介绍如何测试迁移实现。
因为原本的数据库没有使用 Room 实现,自然我们就没有相应的 JSON 文件,因此我们无法使用 MigrationTestHelper 创建数据库。
我们需要这么做:
扩展 SQLiteOpenHelper 类,并在 onCreate 执行创建数据库表的 SQL 查询操作;
在 @Before 测试方法中,创建数据库;
在 @After 测试方法中,清除数据库;
使用 SQLiteOpenHelper ,来插入测试所需的数据,检查从 SQLiteDatabase 版本迁移到使用 Room 的版本;
使用 MigrationTestHelper 运行迁移和验证 schema;
检查数据库数据的有效性。
数据库版本 1 使用 SQLiteDatabase 实现,然后在版本 2 中,我们迁移到了 Room,而在版本 3 中,我们添加了一个新的列。检查从版本 1 到 3 的迁移测试如下所示:
@Test
public void migrationFrom1To3_containsCorrectData() throws IOException {
// Create the database with the initial version 1 schema and
//insert a user
SqliteDatabaseTestHelper.insertUser(1, USER.getUserName(), sqliteTestDbHelper);
// Re-open the database with version 3 and provide MIGRATION_1_2
// and MIGRATION_2_3 as the migration process.
testHelper.runMigrationsAndValidate(TEST_DB_NAME, 3, true,
MIGRATION_1_2, MIGRATION_2_3);
// Get the latest, migrated, version of the database
// Check that the correct data is in the database
User dbUser = getMigratedRoomDatabase().userDao().getUser();
assertEquals(dbUser.getId(), 1);
assertEquals(dbUser.getUserName(), USER.getUserName());
// The date was missing in version 2, so it should be null in
//version 3
assertEquals(dbUser.getDate(), null);
}
挽起袖子试试吧!
这里有一个示例 App:
https://github.com/googlesamples/android-architecture-components/tree/master/PersistenceMigrationsSample
您可以在此示例应用中查看实现。为了简化比较,每个数据库版本都是以自己的风格实现的,相信看完之后您已经能玩转典型的迁移路径了:
sqlite:使用 SQLiteOpenHelper 和传统的 SQLite 界面;
room :使用 Room 替换实现,并提供到版本 2 的迁移;
room2:将数据库更新为新 schema,版本 3;
room3: 将数据库更新为新的版本 4。提供从版本 2 到 3,版本 3 到 4,以及版本 1 到 4 的迁移路径。
使用 Room,您可以很容易地实施和测试迁移。MigrationTestHelper 允许您在任何版本打开数据库、运行迁移,并且只需几行代码就可以验证 schema。
您是否已经开始使用 Room 并实施迁移?如果答案是肯定的话,请在下面写出评论,让我们了解您的想法和问题。
推荐阅读: