Android O 遷移測試:Room
在之前的一篇文章中,我們介紹了一下構件組件,其中就提到了使用 Room 來進行數(shù)據庫操作。但我們也有注意到,如果您錯誤地實施遷移,最嚴重的結果可能會導致您的應用崩潰或丟失用戶數(shù)據。
除此之外,Migration.migrate 在編譯時不會檢查在方法中執(zhí)行的 SQL 語句,這導致了更多的問題。了解到這個情況之后,對遷移進行測試就成了一項必做任務。 Room 提供了 MigrationTestHelper 測試工具,這一工具允許您:
- 在給定的版本中創(chuàng)建一個數(shù)據庫
- 在數(shù)據庫上運行一組給定的遷移
- 驗證數(shù)據庫 schema
當然,Room 不會驗證數(shù)據庫中的數(shù)據本身。這是您需要親自去實現(xiàn)的東西。
以下是您需要了解的有關 Room 遷移測試的內容。
工作原理
為了進行遷移測試,Room 需要知道您當前數(shù)據庫版本的幾個要素:版本號、Entity、Identity Hash,以及為創(chuàng)建和更新 room_master_table 而做出的查詢請求。所有這些都由 Room 在編譯時自動生成,并存儲在schema JSON 文件中。
在 build.gradle 文件中指定一個文件夾,來放置這些生成的 schema JSON 文件。在更新 schema 時,最終會出現(xiàn)一些 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”
- }
遷移測試規(guī)則
創(chuàng)建數(shù)據庫和 schema,打開和關閉數(shù)據庫,運行遷移 —— 您幾乎需要為每個測試編寫大量這樣的樣板代碼。為了避免過度重復勞動,請在遷移測試類中使用 MigrationTestHelper 測試工具。
為了創(chuàng)建數(shù)據庫以及驗證遷移,MigrationTestHelper 很大程度上依賴于生成的 JSON 文件。
- @Rule
- public MigrationTestHelper testHelper =
- new MigrationTestHelper(
- InstrumentationRegistry.getInstrumentation(),
- <your_database_class>.class.getCanonicalName(),
- new FrameworkSQLiteOpenHelperFactory()
您可以在特定版本中創(chuàng)建數(shù)據庫:
- // Create the database with version 2
- SupportSQLiteDatabase db =
- testHelper.createDatabase(TEST
您可以運行一組遷移,并自動驗證 schema 是否更新無誤:
- db = testHelper.runMigrationsAndValidate(TEST_DB_NAME, 4, validateDroppe
實施測試
測試策略很簡單:
- 在特定版本中打開數(shù)據庫;
- 插入一些數(shù)據;
- 運行遷移并驗證 schema;
- 檢查數(shù)據庫中是否有正確的數(shù)據。
例如,數(shù)據庫的版本 3 添加了一個新列:date 。因此,當測試從版本 2 到版本 3 的遷移時,我們檢查插入到版本 2 的數(shù)據的有效性,也是我們新列的默認值。我們的 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 的步驟雖然乍一看很直觀,但我們覺得有必要詳細介紹如何測試遷移實現(xiàn)。
因為原本的數(shù)據庫沒有使用 Room 實現(xiàn),自然我們就沒有相應的 JSON 文件,因此我們無法使用 MigrationTestHelper 創(chuàng)建數(shù)據庫。
我們需要這么做:
- 擴展 SQLiteOpenHelper 類,并在 onCreate 執(zhí)行創(chuàng)建數(shù)據庫表的 SQL 查詢操作;
- 在 @Before 測試方法中,創(chuàng)建數(shù)據庫;
- 在 @After 測試方法中,清除數(shù)據庫;
- 使用 SQLiteOpenHelper ,來插入測試所需的數(shù)據,檢查從SQLiteDatabase 版本遷移到使用 Room 的版本;
- 使用 MigrationTestHelper 運行遷移和驗證 schema;
- 檢查數(shù)據庫數(shù)據的有效性。
數(shù)據庫版本 1 使用 SQLiteDatabase 實現(xiàn),然后在版本 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
您可以在此示例應用中查看實現(xiàn)。為了簡化比較,每個數(shù)據庫版本都是以自己的風格實現(xiàn)的,相信看完之后您已經能玩轉典型的遷移路徑了:
- sqlite:使用 SQLiteOpenHelper 和傳統(tǒng)的 SQLite 界面;
- room :使用 Room 替換實現(xiàn),并提供到版本 2 的遷移;
- room2:將數(shù)據庫更新為新 schema,版本 3;
- room3: 將數(shù)據庫更新為新的版本 4。提供從版本 2 到 3,版本 3 到 4,以及版本 1 到 4 的遷移路徑。
使用 Room,您可以很容易地實施和測試遷移。MigrationTestHelper 允許您在任何版本打開數(shù)據庫、運行遷移,并且只需幾行代碼就可以驗證 schema。
【本文是51CTO專欄機構“谷歌開發(fā)者”的原創(chuàng)稿件,轉載請聯(lián)系原作者(微信公眾號:Google_Developers)】