バックアップと復元の自動テスト

ユーザーが新しいデバイスをセットアップしたり、アプリを再インストールしたりすると、Android はクラウド バックアップまたはデバイス間転送からアプリのデータを復元できます。バックアップ ルールで重要なデータが除外されている場合や、アプリが復元したデータを使用できない場合、ユーザーはエラーが表示されることなく設定や進行状況を失うことになります。

自動バックアップと復元のテストは、アプリをリリースする前にこれらの問題を検出するのに役立ちます。これらは、開発マシンで実行され、Android Debug Bridge(adb)を介して接続されたデバイスを制御する JUnit 5 テストです。各テストでは、デバイスにアプリデータをシードし、Android バックアップ フレームワークを介してアプリのバックアップと復元を行い、データがそのまま残っていることを確認します。テストは、モジュールのビルドファイルで Android Gradle プラグイン(AGP)のテストスイートとして構成します。

仕組み

バックアップと復元のテストスイートは、連携して動作する次の 2 つの部分で構成されています。

  • ホストテストは、開発マシンで実行される JUnit 5 テストです。各デバイスで BackupRestoreController を使用して、データのシード、アプリのバックアップと復元、結果の確認を行います。
  • デバイス アクションは、BackupDeviceAction を実装するクラスです。デバイス上のアプリのプロセスで実行されるため、アプリ独自のコードを介してデータの読み取りと書き込みを行うことができます。ホストテストは、クラス名でデバイス アクションを呼び出します。

スイートを実行すると、AGP はアプリと、デバイス アクションを含むテスト APK をビルドします。テスト フレームワークは、テストで使用する各デバイスに両方の APK をインストールし、各テストの前にアプリのデータを消去します。

組み込みストレージ タイプ

次の表に、デバイス アクションを記述せずにデータのシードと検証を行うことができる StorageDomain サブクラスを示します。

ストレージ ドメイン データ
StorageDomain.Preference SharedPreferences ファイル内の鍵。
StorageDomain.Database SQLite データベース テーブルの行。
StorageDomain.TextFile アプリの内部ストレージ内のテキスト ファイル。
StorageDomain.BinaryFile アプリの内部ストレージにあるバイナリ ファイル。

DataStore ファイルなどの他のデータをテストするには、デバイス アクションを記述します。

移動手段

各バックアップは BackupTransportMode 値を使用します。次の表に、サポートされている移動手段を示します。

モード シナリオ
LOCAL デバイスのローカル バックアップ トランスポートへのバックアップ。バックアップ データはデバイスに残ります。
CLOUD_ENCRYPTED クラウド バックアップ(クライアントサイド暗号化が有効なデバイスからユーザーの Google アカウントに保存されたバックアップなど)。
CLOUD_UNENCRYPTED クライアントサイド暗号化が設定されていないデバイスからのクラウド バックアップ。
DEVICE_TO_DEVICE デバイス間転送(ケーブルや Wi-Fi 経由など)。

LOCAL は、サポートされているすべてのデバイスで動作します。クラウドモードとデバイス間モードでは、Android Studio の [Backup App Data] アクションと同じバックアップが作成されます。バックアップは、アップロードまたは別のデバイスに送信されるのではなく、開発マシンに保存されます。クラウドモードとデバイス間モードでは、デバイスに Google Play 開発者サービスがインストールされていることと、アプリのデバッグ可能なビルドが必要です。バックアップ ルールがクライアントサイドの暗号化に依存している場合は、両方のクラウドモードをテストします。

要件

自動バックアップと復元のテストを使用するには、環境が次の要件を満たしていることを確認してください。

  • Gradle バージョン 9.6.0 以降。
  • JDK バージョン 17 以降。
  • Android 12(API レベル 31)以降を搭載し、adb 経由で接続されているデバイスまたはエミュレータ。
    • API レベル 36.1 以降のデバイスまたはエミュレータには、Google Play 開発者サービス バージョン 26.33.30 以降が必要です。
    • 2 台のデバイス間の転送をテストするには、2 台のデバイスを接続します。

互換性

次の表に、自動バックアップと復元のテストの最小バージョンと推奨バージョンを示します。

コンポーネント 最小バージョン 推奨バージョン
Android Studio Rabbit 2 Canary 1 Rabbit 2 Canary 4 以降
Android Gradle プラグイン(AGP) 9.5.0-alpha06 9.5.0-alpha09 以降
androidx.test.backup 個のライブラリ 1.0.0-alpha01 1.0.0-alpha03 以降

AGP の各プレビュー版には、対応するプレビュー版の Android Studio が必要です。詳しくは、AGP プレビューをご覧ください。

プロジェクトを設定する

バックアップと復元のテストスイートをアプリ モジュールに追加する手順は次のとおりです。

試験運用版フラグを有効にする

プロジェクトの gradle.properties ファイルで、テストスイートとバックアップ テストを有効にします。

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

テストスイートを宣言する

アプリ モジュールの build.gradle.kts ファイルで、testOptions ブロックにバックアップ テストスイートを宣言します。

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

この例では、スイート名 backupTest によって、ソースセット ディレクトリと Gradle タスク名が決まります。次のオプション プロパティを使用して、スイートをカスタマイズできます。

  • backupTestLibraryVersion を使用して、AGP がスイートに追加する androidx.test.backup ライブラリ("1.0.0-alpha03" など)のバージョンを設定します。このプロパティは省略可能です。省略すると、AGP は AGP バージョンに基づいてデフォルトのライブラリ バージョンにフォールバックします。このページの例では、バージョン 1.0.0-alpha03 以降が必要です。
  • targetVariants を使用して、スイートがテストするビルド バリアント(targetVariants.add("demoDebug") など)を指定します。このプロパティは省略可能です。省略すると、スイートはモジュールの testBuildType のバリアントをテストします。デフォルトは debug です。クラウドとデバイス間の転送モードではデバッグ可能なアプリが必要になるため、デバッグ可能なバリアントをテストすることをおすすめします。

AGP は、ホスト ライブラリ androidx.test.backup:backup-host と JUnit 5 をホストテストに追加します。デバイス ライブラリ androidx.test.backup:backup をテスト APK に追加し、テスト APK のインストルメンテーション ランナーを設定します。

他の依存関係を追加するには、スイートの hostJar ブロックと testApk ブロックを使用します。たとえば、ホストテストで Truth を使用するには、hostJar ブロックに追加します。

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

ソースセットを作成する

スイート名と一致するソースセット ディレクトリを作成します。

  • ホストテストを src/{suiteName}/test/kotlin/ に配置します。
  • デバイス アクションを src/{suiteName}/androidTest/kotlin/ に配置します。

たとえば、backupTest という名前のスイートでは、次のディレクトリ構造を使用します。

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

バックアップ構成を確認する

テストでは、アプリのバックアップ構成に含まれるデータをバックアップして復元します。アプリでバックアップが有効になっていること、バックアップ ルールにテストするデータが含まれていることを確認します。

バックアップと復元のテストを作成する

スイートの test ソースセットにホストテストを作成します。各テストクラスに @ExtendWith(BackupRestoreExtension::class) アノテーションを付けます。これにより、接続されたデバイスがテストに提供されます。テストは、スイートがターゲットとするアプリ バリアントに対して実行されるため、アプリケーション ID を設定する必要はありません。

各テストメソッドは、使用するデバイスごとに BackupRestoreController パラメータを宣言します。

組み込みストレージ タイプをテストする

組み込みのストレージ タイプをテストするには、シードするデータ、バックアップ ファイルのディレクトリ、トランスポート モードを指定して runBackupRestoreFlow を呼び出します。このメソッドは、デバイスで次の手順を実行します。

  1. 各ストレージ ドメインをシードします。
  2. アプリを停止します。
  3. アプリをバックアップします。
  4. アプリのデータを消去します。
  5. バックアップを復元します。
  6. 各ストレージ ドメインにシード値があることを確認します。

ステップが失敗すると、メソッドは例外をスローし、テストは失敗します。次の例では、ローカル バックアップ トランスポートを使用して、SharedPreferences キー、SQLite 行、内部ファイルをテストします。

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,
        )
    }
}

ストレージ ドメインを定義する際は、次の点に注意してください。

  • Preference は、.xml 拡張子なしの SharedPreferences ファイルの名前を受け取ります。
  • TextFile と BinaryFile は、アプリの filesDir に対する相対パスを解決します。
  • Database は SQL で行を書き込み、テーブルが存在しない場合は TEXT 列を含むテーブルを作成します。アプリで Room を使用している場合は、DAO を使用するデバイス アクションでデータベース コンテンツをテストし、データベースに Room が想定するスキーマが含まれるようにすることをおすすめします。

デバイス アクションを書き込む

組み込みのストレージ タイプでカバーされていないデータをシードまたは検証するには、スイートの androidTest ソースセットにデバイス アクションを記述します。デバイス アクションは BackupDeviceAction を実装し、次の 2 つのメンバーをオーバーライドします。

  • データをシードするアクションの場合は phase を BackupDeviceAction.PHASE_POPULATE に設定し、データをチェックするアクションの場合は BackupDeviceAction.PHASE_VERIFY に設定します。
  • execute を実装して、アプリの Context とホストテストの引数を使用してアクションを実行します。BackupDeviceActionResult.success または BackupDeviceActionResult.failure ファクトリ メソッドで作成された結果を返し、エラー メッセージを failure に渡します。

execute メソッドは、バックグラウンド スレッドのアプリのプロセスで実行されるため、読み取りと書き込みが完了するまでブロックできます。

次の例では、アプリが Preferences DataStore に保存するテーマ設定をシードして検証します。アプリは、メインのソースセットで DataStore を定義します。

// 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")

デバイス アクションは同じ定義を使用します。

// 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")
        }
    }
}

ホストテストにデータを返すには、success メソッドにマップを渡します。ホストテストは BackupActionResult.Success.data からマップを読み取ります。

フローの各ステップを実行する

デバイス アクションを使用する場合や、フローをカスタマイズする場合は、各ステップを自分で呼び出します。次のホストテストでは、クラウドのバックアップと復元に関する前のセクションのデバイス アクションを実行します。

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)
}

デバイス アクションが失敗すると、runOnDevice は例外をスローする代わりに BackupActionResult.Failure を返すため、結果を確認してください。他のステップは、失敗すると例外をスローします。

デバイス間の転送をテストする

2 つのデバイス間の転送をテストするには、デバイスごとに BackupRestoreController パラメータを宣言します。ソースデバイスでアプリをバックアップし、対象デバイスでバックアップ ファイルを復元します。次の例では、前の例の定数と assertSuccess ヘルパーを再利用しています。

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()
    }
}

@Device の role 値を使用すると、テストの実行時にパラメータごとにデバイスを選択できます。1 台のデバイスのみが接続されている場合、両方のパラメータでそのデバイスが使用され、テストでは 1 台のデバイスでの転送がシミュレートされます。ターゲットのデータを消去すると、復元されたデータがバックアップから取得されます。

デバイスの選択

デフォルトでは、テスト フレームワークはオンライン デバイスをシリアル番号で並べ替え、各テストの BackupRestoreController パラメータに順番に割り当てます。テストにデバイスよりも多くのデバイス パラメータがある場合、追加のパラメータは最初のデバイスを共有します。ANDROID_SERIAL 環境変数はデバイスの割り当てに影響しません。

テストにシリアル番号を入れずにデバイスを選択するには、@Device(role = "...") を使用して各デバイス パラメータにロールを割り当てます。次に、テストを実行するときに、androidx.test.backup.device.serial.{role} システム プロパティを使用して各ロールをデバイスにバインドします。たとえば、次のコマンドは、emulator-5554 をソースデバイス、emulator-5556 を対象デバイスとしてスイートを実行します。

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

バインディングは、そのロールを持つパラメータにのみ適用されます。その他のパラメータは、残りのデバイスを取得します。

serial と api の値が @Device のデバイス、または次のシステム プロパティを持つデバイスを選択することもできます。これらのプロパティは @Device の値よりも優先されます。

システム プロパティ 説明
androidx.test.backup.device.serial.{role} @Device(role = "{role}") でアノテーションが付けられたパラメータのデバイスのシリアル番号。serials と serial よりも優先されます。
androidx.test.backup.device.serials シリアル番号のカンマ区切りのリスト。デバイス パラメータに順番に割り当てられます。
androidx.test.backup.device.serial serials でカバーされていないデバイス パラメータのデバイスのシリアル番号。
androidx.test.backup.device.apis API レベルのカンマ区切りのリスト。デバイス パラメータに順番に割り当てられます。
androidx.test.backup.device.api apis でカバーされていないデバイス パラメータのデバイスの API レベル。

これらのプロパティを -D と同じ方法で渡します。serial、serials、api、apis プロパティは、実行されるすべてのテストに適用されるため、--tests オプションを使用して、それらを必要とするテストのみを実行します。

テスト用認証情報の復元

アプリで Restore Credentials を使用している場合は、バックアップと復元を行っても復元キーが保持されることをテストします。クラウドモードとデバイス間モードでは、アプリのデータとともに鍵がバックアップされますが、LOCAL ではバックアップされません。

キーを作成し、認証情報マネージャーで取得するデバイス アクションを作成します。create アクションは鍵の認証情報 ID を返します。これにより、verify アクションは、復元によって同じ鍵が戻されることを確認できます。この例では、createRequestJson と getRequestJson は、アプリが認証情報マネージャーに渡すリクエスト JSON 文字列です。

// 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")
        }
    }
}

次のホストテストでは、ソースデバイスで鍵を作成し、対象デバイスで復元して、そこで確認します。フローの各ステップを実行するの assertSuccess ヘルパーを使用します。

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()
    }
}

isCloudBackupEnabled をデフォルトの true に設定してキーを作成するには、ソースデバイスにバックアップが有効になっている Google アカウントと画面ロックが必要です。それ以外の場合、認証情報マネージャーは E2eeUnavailableException をスローします。

新しいデバイスでのクラウド復元とは異なり、クラウドモードでは、同じ Google アカウントやソースデバイスの画面ロックは必要ありません。また、isCloudBackupEnabled を false に設定して作成された鍵が復元されます。

テスト間でアプリデータを保持する

各テストの前に、テスト フレームワークは、テストで使用する各デバイス上のアプリのデータを消去します。テストクラスまたはメソッドでこの機能をオフにするには、@Isolation(IsolationPolicy.MANUAL) アノテーションを付けます。

Java でテストを作成する

BackupRestoreController メソッドは Kotlin の suspend 関数です。Java でホストテストを作成する場合は、各メソッドの Async バリアント(ListenableFuture を返す runBackupRestoreFlowAsync など)を使用します。

バックアップと復元のテストを実行する

AGP は、スイートがテストするバリアントごとに、test{Variant}{SuiteName}DefaultTestSuite という名前の Gradle タスクを作成します。debug バリアントに対して backupTest スイートを実行するには、デバイスを接続して次のタスクを実行します。

./gradlew :app:testDebugBackupTestDefaultTestSuite

check、test、connectedCheck タスクはバックアップと復元のテストスイートを実行しないため、スイートのタスクを明示的に実行します。

単一のテストクラスまたはメソッドを実行するには、--tests オプションを使用します。

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

テストレポートを検査する

テスト実行が完了すると、AGP は {module}/build/reports/tests/{taskName}/index.html(app/build/reports/tests/testDebugBackupTestDefaultTestSuite/index.html など)に HTML テストレポートを生成します。

復元の失敗に関するトラブルシューティング

次の場合、クラウドまたはデバイス間の復元が失敗し、エラー メッセージが表示されます。

  • Google Play 開発者サービスがアプリをスキップする。たとえば、アプリケーション ID が com.google. または com.android. で始まる、バックアップが空である、android:allowBackup="false" が設定されているなどの理由が考えられます。このようなアプリケーション ID を持つアプリをテストするには、LOCAL モードを使用します。
  • API レベル 36.1 以降を搭載したデバイスまたはエミュレータで、Google Play 開発者サービスのバージョンが 26.33.30 未満である。デバイスの Google Play ストアから Google Play 開発者サービスを更新するか、バージョン 26.33.30 以降が付属するシステム イメージを使用してください。

既知の問題と制限事項

自動バックアップと復元のテストには、次の既知の問題と制限事項があります。

  • Android Studio でのテストスイートのサポートはまだ利用できません。プロジェクトが正しく構成されている場合でも、コードエディタでテストスイートのソースファイルに未解決の参照エラーが表示されることがあります。代わりに、Gradle を使用してコマンドラインからバックアップと復元のテストをビルドして実行します。
  • テストは、adb を介して開発マシンに接続されているデバイスとエミュレータでのみ実行されます。Firebase Test Lab はサポートされていません。
  • テストでは、アプリのデータが消去され、使用するデバイスのバックアップ設定が変更されます。専用のテストデバイスを使用することをおすすめします。

各リリースの変更点については、バックアップと復元のテストのリリースノートをご覧ください。