Pengujian pencadangan dan pemulihan otomatis

Saat pengguna menyiapkan perangkat baru atau menginstal ulang aplikasi Anda, Android dapat memulihkan data aplikasi Anda dari pencadangan cloud atau transfer antarperangkat. Jika aturan pencadangan Anda mengabaikan data penting, atau aplikasi Anda tidak dapat menggunakan data yang dipulihkan, pengguna akan kehilangan setelan dan progresnya tanpa melihat error.

Pengujian pencadangan dan pemulihan otomatis membantu Anda mendeteksi masalah ini sebelum merilis aplikasi. Pengujian ini adalah pengujian JUnit 5 yang berjalan di mesin pengembangan dan mengontrol perangkat terhubung melalui Android Debug Bridge (adb). Setiap pengujian menyisipkan data aplikasi di perangkat, mencadangkan dan memulihkan aplikasi melalui framework pencadangan Android, lalu memeriksa apakah data tersebut utuh. Anda mengonfigurasi pengujian sebagai suite pengujian plugin Android Gradle (AGP) dalam file build modul.

Cara kerjanya

Suite pengujian pencadangan dan pemulihan memiliki dua bagian yang bekerja sama:

  • Pengujian host adalah pengujian JUnit 5 yang berjalan di mesin pengembangan Anda. Mereka menggunakan BackupRestoreController untuk setiap perangkat guna menyisipkan data, mencadangkan dan memulihkan aplikasi, serta memeriksa hasilnya.
  • Tindakan perangkat adalah class yang mengimplementasikan BackupDeviceAction. Pengujian ini berjalan dalam proses aplikasi Anda di perangkat, sehingga dapat membaca dan menulis data melalui kode aplikasi Anda sendiri. Pengujian host memanggil tindakan perangkat berdasarkan nama class.

Saat Anda menjalankan suite, AGP akan mem-build aplikasi dan APK pengujian yang berisi tindakan perangkat Anda. Framework pengujian menginstal kedua APK di setiap perangkat yang digunakan pengujian dan menghapus data aplikasi Anda sebelum setiap pengujian.

Jenis penyimpanan bawaan

Tabel berikut mencantumkan subclass StorageDomain yang memungkinkan Anda menyisipkan dan memverifikasi data tanpa menulis tindakan perangkat:

Domain penyimpanan Data
StorageDomain.Preference Kunci dalam file SharedPreferences.
StorageDomain.Database Baris dalam tabel database SQLite.
StorageDomain.TextFile File teks di penyimpanan internal aplikasi Anda.
StorageDomain.BinaryFile File biner di penyimpanan internal aplikasi Anda.

Untuk menguji data lain, seperti file DataStore, tulis tindakan perangkat.

Moda transportasi

Setiap cadangan menggunakan nilai BackupTransportMode. Tabel berikut mencantumkan mode transportasi yang didukung:

Mode Skenario
LOCAL Pencadangan ke transpor pencadangan lokal perangkat. Data cadangan tetap berada di perangkat.
CLOUD_ENCRYPTED Cadangan cloud, seperti yang disimpan ke Akun Google pengguna dari perangkat dengan enkripsi sisi klien.
CLOUD_UNENCRYPTED Cadangan cloud dari perangkat yang tidak memiliki enkripsi sisi klien.
DEVICE_TO_DEVICE Transfer antarperangkat, misalnya melalui kabel atau Wi-Fi.

LOCAL berfungsi di perangkat apa pun yang didukung. Mode cloud dan perangkat ke perangkat membuat cadangan yang sama dengan tindakan Backup App Data di Android Studio: cadangan disimpan ke mesin pengembangan, bukan diupload atau dikirim ke perangkat lain. Mode cloud dan perangkat ke perangkat memerlukan layanan Google Play di perangkat dan build aplikasi yang dapat di-debug. Jika aturan pencadangan Anda bergantung pada enkripsi sisi klien, uji kedua mode cloud.

Persyaratan

Untuk menggunakan pengujian pencadangan dan pemulihan otomatis, pastikan lingkungan Anda memenuhi persyaratan berikut:

  • Gradle versi 9.6.0 atau yang lebih tinggi.
  • JDK versi 17 atau yang lebih baru.
  • Perangkat atau emulator yang menjalankan Android 12 (level API 31) atau yang lebih tinggi yang terhubung melalui adb:
    • Perangkat atau emulator di level API 36.1 atau yang lebih tinggi memerlukan layanan Google Play versi 26.33.30 atau yang lebih tinggi.
    • Untuk menguji transfer antara dua perangkat, hubungkan dua perangkat.

Kompatibilitas

Tabel berikut mencantumkan versi minimum dan yang direkomendasikan untuk pengujian pencadangan dan pemulihan otomatis:

Komponen Versi minimum Versi yang direkomendasikan
Android Studio Rabbit 2 Canary 1 Rabbit 2 Canary 4 atau yang lebih tinggi
Plugin Android Gradle (AGP) 9.5.0-alpha06 9.5.0-alpha09 atau yang lebih tinggi
androidx.test.backup library 1.0.0-alpha01 1.0.0-alpha03 atau yang lebih tinggi

Setiap versi pratinjau AGP memerlukan versi pratinjau Android Studio yang sesuai. Untuk mengetahui informasi selengkapnya, lihat Pratinjau AGP.

Menyiapkan project

Untuk menambahkan suite pengujian pencadangan dan pemulihan ke modul aplikasi, selesaikan langkah-langkah berikut:

Mengaktifkan tanda eksperimental

Dalam file gradle.properties project Anda, aktifkan suite pengujian dan pengujian cadangan:

android.experimental.testSuiteSupport=true
android.experimental.enableBackupTest=true

Mendeklarasikan suite pengujian

Dalam file build.gradle.kts modul aplikasi, deklarasikan suite pengujian pencadangan di blok testOptions:

android {
    testOptions {
        backupTests {
            create("backupTest") {
                backupTestLibraryVersion = "1.0.0-alpha03"
            }
        }
    }
}

Nama suite, backupTest dalam contoh ini, menentukan direktori set sumber dan nama tugas Gradle. Anda dapat menyesuaikan suite dengan properti opsional berikut:

  • Gunakan backupTestLibraryVersion untuk menetapkan versi library androidx.test.backup yang ditambahkan AGP ke suite, seperti "1.0.0-alpha03". Properti ini bersifat opsional. Jika Anda menghilangkannya, AGP akan kembali ke versi library default berdasarkan versi AGP. Contoh di halaman ini memerlukan versi 1.0.0-alpha03 atau yang lebih tinggi.
  • Gunakan targetVariants untuk menentukan varian build yang diuji suite, seperti targetVariants.add("demoDebug"). Properti ini bersifat opsional. Jika Anda menghilangkannya, suite akan menguji varian testBuildType modul Anda, yang secara default adalah debug. Sebaiknya uji varian yang dapat di-debug karena mode transportasi cloud dan perangkat ke perangkat memerlukan aplikasi yang dapat di-debug.

AGP menambahkan library host, androidx.test.backup:backup-host, dan JUnit 5 ke pengujian host. Tindakan ini akan menambahkan library perangkat, androidx.test.backup:backup, ke APK pengujian dan menetapkan runner instrumentasi APK pengujian.

Untuk menambahkan dependensi lain, gunakan blok hostJar dan testApk dari suite. Misalnya, untuk menggunakan Truth dalam pengujian host, tambahkan ke blok hostJar:

create("backupTest") {
    hostJar {
        dependencies {
            implementation("com.google.truth:truth:1.4.2")
        }
    }
}

Membuat set sumber

Buat direktori set sumber yang cocok dengan nama suite:

  • Tempatkan pengujian host di src/{suiteName}/test/kotlin/.
  • Tempatkan tindakan perangkat di src/{suiteName}/androidTest/kotlin/.

Misalnya, suite bernama backupTest menggunakan struktur direktori berikut:

app/src/backupTest/
├── androidTest/
│   └── kotlin/com/example/myapp/ThemeActions.kt
└── test/
    └── kotlin/com/example/myapp/SettingsBackupTest.kt

Memeriksa konfigurasi cadangan Anda

Menguji pencadangan dan pemulihan data yang disertakan dalam konfigurasi pencadangan aplikasi Anda. Pastikan pencadangan diaktifkan untuk aplikasi Anda dan aturan pencadangan menyertakan data yang Anda uji.

Menulis pengujian pencadangan dan pemulihan

Tulis pengujian host di set sumber test suite. Anotasikan setiap class pengujian dengan @ExtendWith(BackupRestoreExtension::class), yang menyediakan perangkat terhubung ke pengujian. Pengujian dijalankan terhadap varian aplikasi yang ditargetkan oleh suite, sehingga Anda tidak perlu menetapkan ID aplikasinya.

Setiap metode pengujian mendeklarasikan parameter BackupRestoreController untuk setiap perangkat yang digunakannya.

Menguji jenis penyimpanan bawaan

Untuk menguji jenis penyimpanan bawaan, panggil runBackupRestoreFlow dengan data yang akan di-seed, direktori untuk file cadangan, dan mode transpor. Metode ini menjalankan langkah-langkah berikut di perangkat:

  1. Menyemai setiap domain penyimpanan.
  2. Menghentikan aplikasi.
  3. Mencadangkan aplikasi.
  4. Menghapus data aplikasi.
  5. Memulihkan cadangan.
  6. Memverifikasi bahwa setiap domain penyimpanan memiliki nilai awal.

Jika sebuah langkah gagal, metode akan menampilkan pengecualian, yang akan menggagalkan pengujian. Contoh berikut menguji kunci SharedPreferences, baris SQLite, dan file internal menggunakan transpor pencadangan lokal:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import androidx.test.backup.host.StorageDomain
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.io.TempDir

@ExtendWith(BackupRestoreExtension::class)
class SettingsBackupTest {

    @Test
    fun settingsSurviveBackupAndRestore(
        device: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        device.runBackupRestoreFlow(
            storages = listOf(
                StorageDomain.Preference(
                    prefName = "settings",
                    key = "theme",
                    value = "dark",
                ),
                StorageDomain.Database(
                    dbName = "notes.db",
                    table = "notes",
                    primaryKeyCol = "id",
                    primaryKeyVal = 1,
                    columnValues = mapOf("title" to "Groceries"),
                ),
                StorageDomain.TextFile(
                    path = "drafts/note.txt",
                    content = "Buy milk",
                ),
            ),
            outputDir = outputDir,
            mode = BackupTransportMode.LOCAL,
        )
    }
}

Perhatikan hal-hal berikut saat Anda menentukan domain penyimpanan:

  • Preference mengambil nama file SharedPreferences tanpa ekstensi .xml.
  • TextFile dan BinaryFile me-resolve jalur relatif terhadap filesDir aplikasi Anda.
  • Database menulis baris dengan SQL, dan membuat tabel dengan kolom TEXT jika tabel tidak ada. Jika aplikasi Anda menggunakan Room, sebaiknya uji konten database dengan tindakan perangkat yang menggunakan DAO Anda sehingga database memiliki skema yang diharapkan Room.

Menulis tindakan perangkat

Untuk menyisipkan atau memverifikasi data yang tidak tercakup dalam jenis penyimpanan bawaan, tulis tindakan perangkat di set sumber androidTest suite. Tindakan perangkat mengimplementasikan BackupDeviceAction dan mengganti dua anggota:

  • Tetapkan phase ke BackupDeviceAction.PHASE_POPULATE untuk tindakan yang menyisipkan data, atau BackupDeviceAction.PHASE_VERIFY untuk tindakan yang memeriksa data.
  • Terapkan execute untuk menjalankan tindakan dengan Context aplikasi Anda dan argumen dari pengujian host. Tampilkan hasil yang dibuat dengan metode factory BackupDeviceActionResult.success atau BackupDeviceActionResult.failure, dan teruskan pesan error ke failure.

Metode execute berjalan dalam proses aplikasi Anda di thread latar belakang, sehingga dapat memblokir hingga operasi baca dan tulis selesai.

Contoh berikut menyisipkan dan memverifikasi setelan tema yang disimpan aplikasi dengan Preferences DataStore. Aplikasi menentukan DataStore dalam set sumber utamanya:

// In app/src/main/kotlin/com/example/myapp/Settings.kt
package com.example.myapp

import android.content.Context
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore

val Context.settingsDataStore by preferencesDataStore(name = "settings")
val THEME_KEY = stringPreferencesKey("theme")

Tindakan perangkat menggunakan definisi yang sama:

// In app/src/backupTest/androidTest/kotlin/com/example/myapp/ThemeActions.kt
package com.example.myapp

import android.content.Context
import androidx.datastore.preferences.core.edit
import androidx.test.backup.BackupDeviceAction
import androidx.test.backup.BackupDeviceActionArgs
import androidx.test.backup.BackupDeviceActionResult
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking

class SeedThemeAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_POPULATE

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val theme = args["theme"]
            ?: return BackupDeviceActionResult.failure("Missing theme argument")
        runBlocking {
            context.settingsDataStore.edit { it[THEME_KEY] = theme }
        }
        return BackupDeviceActionResult.success()
    }
}

class VerifyThemeAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_VERIFY

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val expected = args["theme"]
        val actual = runBlocking {
            context.settingsDataStore.data.first()[THEME_KEY]
        }
        return if (actual == expected) {
            BackupDeviceActionResult.success()
        } else {
            BackupDeviceActionResult.failure("Expected $expected, found $actual")
        }
    }
}

Untuk menampilkan data ke pengujian host, teruskan peta ke metode success. Pengujian host membaca peta dari BackupActionResult.Success.data.

Menjalankan setiap langkah alur

Untuk menggunakan tindakan perangkat, atau untuk menyesuaikan alur, panggil setiap langkah sendiri. Pengujian host berikut menjalankan tindakan perangkat dari bagian sebelumnya seputar pencadangan dan pemulihan cloud:

package com.example.myapp

import androidx.test.backup.host.BackupActionResult
import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.fail
import org.junit.jupiter.api.io.TempDir

const val SEED_THEME = "com.example.myapp.SeedThemeAction"
const val VERIFY_THEME = "com.example.myapp.VerifyThemeAction"

@ExtendWith(BackupRestoreExtension::class)
class ThemeBackupTest {

    @Test
    fun themeSurvivesCloudBackup(
        device: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        val args = mapOf("theme" to "dark")
        device.runOnDevice(SEED_THEME, args).assertSuccess()

        device.stopApp()
        val backupFile = device.performBackup(
            BackupTransportMode.CLOUD_ENCRYPTED,
            outputDir,
        )
        device.clearAppData()
        device.performRestore(backupFile)

        device.runOnDevice(VERIFY_THEME, args).assertSuccess()
    }
}

fun BackupActionResult.assertSuccess() {
    if (this is BackupActionResult.Failure) fail(errorMessage)
}

Jika tindakan perangkat gagal, runOnDevice akan menampilkan BackupActionResult.Failure, bukan menampilkan pengecualian, jadi periksa hasilnya. Langkah-langkah lainnya akan menampilkan pengecualian jika gagal.

Menguji transfer antarperangkat

Untuk menguji transfer antara dua perangkat, deklarasikan parameter BackupRestoreController untuk setiap perangkat. Cadangkan aplikasi di perangkat sumber, lalu pulihkan file cadangan di perangkat target. Contoh berikut menggunakan kembali konstanta dan helper assertSuccess dari contoh sebelumnya:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import androidx.test.backup.host.Device
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.io.TempDir

@ExtendWith(BackupRestoreExtension::class)
class ThemeTransferTest {

    @Test
    fun themeTransfersToNewDevice(
        @Device(role = "source") source: BackupRestoreController,
        @Device(role = "target") target: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        val args = mapOf("theme" to "dark")
        source.runOnDevice(SEED_THEME, args).assertSuccess()
        source.stopApp()
        val backupFile = source.performBackup(
            BackupTransportMode.DEVICE_TO_DEVICE,
            outputDir,
        )

        target.clearAppData()
        target.performRestore(backupFile)
        target.runOnDevice(VERIFY_THEME, args).assertSuccess()
    }
}

Nilai role dari @Device memungkinkan Anda memilih perangkat untuk setiap parameter saat menjalankan pengujian. Jika hanya satu perangkat yang terhubung, kedua parameter akan menggunakan perangkat tersebut, dan pengujian akan menyimulasikan transfer pada satu perangkat. Menghapus data target akan memastikan bahwa data yang dipulihkan berasal dari cadangan.

Pilih perangkat

Secara default, framework pengujian mengurutkan perangkat online berdasarkan nomor seri dan menetapkannya ke parameter BackupRestoreController dari setiap pengujian secara berurutan. Jika pengujian memiliki lebih banyak parameter perangkat daripada jumlah perangkat, parameter tambahan akan menggunakan perangkat pertama. Variabel lingkungan ANDROID_SERIAL tidak memengaruhi penetapan perangkat.

Untuk memilih perangkat tanpa memasukkan nomor seri dalam pengujian, berikan peran pada setiap parameter perangkat dengan @Device(role = "..."). Kemudian, saat Anda menjalankan pengujian, ikat setiap peran ke perangkat dengan properti sistem androidx.test.backup.device.serial.{role}. Misalnya, perintah berikut menjalankan suite dengan emulator-5554 sebagai perangkat sumber dan emulator-5556 sebagai perangkat target:

./gradlew :app:testDebugBackupTestDefaultTestSuite -Dandroidx.test.backup.device.serial.source=emulator-5554 -Dandroidx.test.backup.device.serial.target=emulator-5556

Binding hanya berlaku untuk parameter dengan peran tersebut. Parameter lainnya mendapatkan perangkat yang tersisa.

Anda juga dapat memilih perangkat dengan nilai serial dan api dari @Device, atau dengan properti sistem berikut, yang lebih diprioritaskan daripada nilai @Device:

Properti sistem Deskripsi
androidx.test.backup.device.serial.{role} Nomor seri perangkat untuk parameter yang dianotasi dengan @Device(role = "{role}"). Kebijakan ini lebih diprioritaskan daripada serials dan serial.
androidx.test.backup.device.serials Daftar nomor seri yang dipisahkan koma, yang ditetapkan ke parameter perangkat secara berurutan.
androidx.test.backup.device.serial Nomor seri perangkat untuk parameter perangkat yang tidak tercakup dalam serials.
androidx.test.backup.device.apis Daftar level API yang dipisahkan koma, yang ditetapkan ke parameter perangkat secara berurutan.
androidx.test.backup.device.api Level API perangkat untuk parameter perangkat yang tidak tercakup dalam apis.

Teruskan properti ini dengan -D dengan cara yang sama. Properti serial, serials, api, dan apis berlaku untuk setiap pengujian yang berjalan, jadi gunakan opsi --tests untuk hanya menjalankan pengujian yang memerlukannya.

Menguji Pemulihan Kredensial

Jika aplikasi Anda menggunakan Restore Credentials, uji apakah kunci pemulihannya bertahan setelah pencadangan dan pemulihan. Mode cloud dan perangkat ke perangkat mencadangkan kunci dengan data aplikasi Anda, tetapi LOCAL tidak.

Tulis tindakan perangkat yang membuat kunci dan mendapatkannya dengan Credential Manager. Tindakan pembuatan menampilkan ID kredensial kunci, sehingga tindakan verifikasi dapat memeriksa apakah pemulihan mengembalikan kunci yang sama. Dalam contoh ini, createRequestJson dan getRequestJson adalah string JSON permintaan yang diteruskan aplikasi Anda ke Credential Manager:

// In app/src/backupTest/androidTest/kotlin/com/example/myapp/RestoreKeyActions.kt
package com.example.myapp

import android.content.Context
import androidx.credentials.CreateRestoreCredentialRequest
import androidx.credentials.CreateRestoreCredentialResponse
import androidx.credentials.CredentialManager
import androidx.credentials.GetCredentialRequest
import androidx.credentials.GetRestoreCredentialOption
import androidx.credentials.RestoreCredential
import androidx.test.backup.BackupDeviceAction
import androidx.test.backup.BackupDeviceActionArgs
import androidx.test.backup.BackupDeviceActionResult
import kotlinx.coroutines.runBlocking
import org.json.JSONObject

class CreateRestoreKeyAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_POPULATE

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val request = CreateRestoreCredentialRequest(createRequestJson)
        val response = runBlocking {
            CredentialManager.create(context).createCredential(context, request)
        } as CreateRestoreCredentialResponse
        val credentialId = JSONObject(response.responseJson).getString("id")
        return BackupDeviceActionResult.success(mapOf("credential_id" to credentialId))
    }
}

class VerifyRestoreKeyAction : BackupDeviceAction {
    override val phase = BackupDeviceAction.PHASE_VERIFY

    override fun execute(
        context: Context,
        args: BackupDeviceActionArgs,
    ): BackupDeviceActionResult {
        val option = GetRestoreCredentialOption(getRequestJson)
        val response = runBlocking {
            CredentialManager.create(context)
                .getCredential(context, GetCredentialRequest(listOf(option)))
        }
        val credential = response.credential as RestoreCredential
        val credentialId = JSONObject(credential.authenticationResponseJson).getString("id")
        val expected = args["credential_id"]
        return if (credentialId == expected) {
            BackupDeviceActionResult.success()
        } else {
            BackupDeviceActionResult.failure("Expected key $expected, found $credentialId")
        }
    }
}

Pengujian host berikut membuat kunci di perangkat sumber, memulihkannya di perangkat target, dan memeriksanya di sana. Fungsi ini menggunakan helper assertSuccess dari Menjalankan setiap langkah flow:

package com.example.myapp

import androidx.test.backup.host.BackupActionResult
import androidx.test.backup.host.BackupRestoreController
import androidx.test.backup.host.BackupRestoreExtension
import androidx.test.backup.host.BackupTransportMode
import androidx.test.backup.host.Device
import java.nio.file.Path
import kotlinx.coroutines.runBlocking
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.junit.jupiter.api.io.TempDir

const val CREATE_RESTORE_KEY = "com.example.myapp.CreateRestoreKeyAction"
const val VERIFY_RESTORE_KEY = "com.example.myapp.VerifyRestoreKeyAction"

@ExtendWith(BackupRestoreExtension::class)
class RestoreKeyTest {

    @Test
    fun restoreKeyTransfersToNewDevice(
        @Device(role = "source") source: BackupRestoreController,
        @Device(role = "target") target: BackupRestoreController,
        @TempDir outputDir: Path,
    ): Unit = runBlocking {
        val created = source.runOnDevice(CREATE_RESTORE_KEY)
        created.assertSuccess()
        val credentialId =
            (created as BackupActionResult.Success).data.getValue("credential_id")
        source.stopApp()
        val backupFile = source.performBackup(
            BackupTransportMode.DEVICE_TO_DEVICE,
            outputDir,
        )

        // Also deletes any restore key on the target.
        target.clearAppData()
        target.performRestore(backupFile)
        target.runOnDevice(VERIFY_RESTORE_KEY, mapOf("credential_id" to credentialId))
            .assertSuccess()
    }
}

Untuk membuat kunci dengan isCloudBackupEnabled yang ditetapkan ke true, yaitu setelan default, perangkat sumber memerlukan Akun Google dengan pencadangan yang diaktifkan dan kunci layar. Jika tidak, Pengelola Kredensial akan menampilkan E2eeUnavailableException.

Tidak seperti pemulihan cloud di perangkat baru, mode cloud tidak memerlukan Akun Google yang sama atau kunci layar perangkat sumber, dan mode ini memulihkan kunci yang dibuat dengan isCloudBackupEnabled yang ditetapkan ke false.

Menyimpan data aplikasi di antara pengujian

Sebelum setiap pengujian, framework pengujian akan menghapus data aplikasi Anda di setiap perangkat yang digunakan pengujian. Untuk menonaktifkan ini untuk class atau metode pengujian, anotasikan dengan @Isolation(IsolationPolicy.MANUAL).

Menulis pengujian di Java

Metode BackupRestoreController adalah fungsi penangguhan Kotlin. Jika Anda menulis pengujian host di Java, gunakan varian Async dari setiap metode, seperti runBackupRestoreFlowAsync, yang menampilkan ListenableFuture.

Menjalankan pengujian pencadangan dan pemulihan

AGP membuat tugas Gradle untuk setiap varian yang diuji oleh suite, yang diberi nama test{Variant}{SuiteName}DefaultTestSuite. Untuk menjalankan suite backupTest terhadap varian debug, hubungkan perangkat Anda dan jalankan tugas:

./gradlew :app:testDebugBackupTestDefaultTestSuite

Tugas check, test, dan connectedCheck tidak menjalankan suite pengujian pencadangan dan pemulihan, jadi jalankan tugas suite secara eksplisit.

Untuk menjalankan satu class atau metode pengujian, gunakan opsi --tests:

./gradlew :app:testDebugBackupTestDefaultTestSuite --tests "com.example.myapp.ThemeBackupTest"

Memeriksa laporan pengujian

Setelah pengujian selesai, AGP akan membuat laporan pengujian HTML di {module}/build/reports/tests/{taskName}/index.html, seperti app/build/reports/tests/testDebugBackupTestDefaultTestSuite/index.html.

Memecahkan masalah pemulihan yang gagal

Pemulihan cloud atau perangkat ke perangkat gagal dengan pesan error dalam kasus berikut:

  • Layanan Google Play melewati aplikasi Anda, misalnya karena ID aplikasinya dimulai dengan com.google. atau com.android., cadangannya kosong, atau menetapkan android:allowBackup="false". Untuk menguji aplikasi dengan ID aplikasi tersebut, gunakan mode LOCAL.
  • Versi layanan Google Play lebih rendah dari 26.33.30 di perangkat atau emulator yang menjalankan level API 36.1 atau yang lebih tinggi. Update layanan Google Play melalui Google Play Store di perangkat, atau gunakan image sistem yang dilengkapi dengan versi 26.33.30 atau yang lebih tinggi.

Masalah umum dan batasan

Pengujian pencadangan dan pemulihan otomatis memiliki masalah umum dan batasan berikut:

  • Dukungan Android Studio untuk suite pengujian belum tersedia. Editor kode mungkin menampilkan error referensi yang belum terselesaikan dalam file sumber suite pengujian, meskipun project Anda dikonfigurasi dengan benar. Sebagai gantinya, build dan jalankan pengujian pencadangan dan pemulihan dari command line menggunakan Gradle.
  • Pengujian hanya berjalan di perangkat dan emulator yang terhubung ke mesin pengembangan Anda melalui adb. Firebase Test Lab tidak didukung.
  • Pengujian akan menghapus data aplikasi Anda dan mengubah setelan pencadangan di perangkat yang digunakan. Sebaiknya gunakan perangkat pengujian khusus.

Untuk mengetahui perubahan di setiap rilis, lihat catatan rilis pengujian pencadangan dan pemulihan.