Edit Module build.gradle.
android {
defaultConfig {
...
javaCompileOptions {
annotationProcessorOptions {
arguments = ["room.schemaLocation": "$projectDir/schemas".toString()]
}
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas".toString())
}
}
dependencies {
// existing
implementation "android.arch.persistence.room:runtime:$android_room_version"
kapt "android.arch.persistence.room:compiler:$android_room_version"
// new
androidTestImplementation "android.arch.persistence.room:testing:$android_room_version"
}NOTE: Make sure exportSchema = true for @Database, else schema json won't be generated and later you might bump into FileNotFoundException: Cannot find the schema file in the assets folder.
@Database(entities = [(Pin::class)], version = 1, exportSchema = true)@TypeConverters(RoomConverters::class)abstract class AppDatabase : RoomDatabase() { abstract fun pinDao(): PinDao}When you compile the app, assets/[DatabaseClassPath] (Android view) or /app/schemas/[DatabaseClassPath] (Project view) is generated with 1.json, 2.json, etc. (the number is the database version).
Perform Android Room database migration.
NOTE: You might want to generate 1.json by performing a compilation first, then only perform the necessary database migration (add new column/table to @Entity and change database version) to generate 2.json.
Create MigrationTest.kt in androidTest.
@RunWith(AndroidJUnit4::class)class MigrationTest { companion object { private const val TAG = "MigrationTest" private const val TEST_DB = "test-db" } lateinit var db: SupportSQLiteDatabase @Rule @JvmField val helper: MigrationTestHelper = MigrationTestHelper(InstrumentationRegistry.getInstrumentation(), AppDatabase::class.java!!.canonicalName, FrameworkSQLiteOpenHelperFactory()) @Before fun setUp() { db = helper.createDatabase(TEST_DB, 1) } @Test fun migrate1To2() { // db has schema version 1. insert some data using SQL queries. // You cannot use DAO classes because they expect the latest schema. // db.execSQL(...); val values = ContentValues() values.put("id", "test01") values.put("name", "Test 01") val id = db.insert("pin", SQLiteDatabase.CONFLICT_REPLACE, values) // Prepare for the next version. db.close() // Re-open the database with version 2 and provide // MIGRATION_1_2 as the migration process. db = helper.runMigrationsAndValidate(TEST_DB, 2, true, MIGRATION_1_2) // MigrationTestHelper automatically verifies the schema changes, // but you need to validate that the data was migrated properly. val cursor = db.query("SELECT * FROM pin WHERE rowid = ?", arrayOf(id)) MatcherAssert.assertThat(cursor, Is(notNullValue())) MatcherAssert.assertThat(cursor.moveToFirst(), Is(true)) val name = cursor.getString("name") MatcherAssert.assertThat(name, Is("Test 01")) val isLocationAccurate = cursor.getIntOrNull("is_location_accurate") // MatcherAssert.assertThat(isLocationAccurate, Is(nullValue())) MatcherAssert.assertThat(isLocationAccurate, Is(0)) }}NOTE: Refer to Android Instrumented Unit Test if you are not familiar with Instrumented Unit Test.
NOTE: If you bump into duplicate column name exception, check schema/1.json and schema/2.json to make sure the new column doesn't exist in schema/1.json.
References: