Pruebas automatizadas de copia de seguridad y restablecimiento

Cuando los usuarios configuran un dispositivo nuevo o reinstalan tu app, Android puede restablecer los datos de la app desde una copia de seguridad en la nube o una transferencia de dispositivo a dispositivo. Si tus reglas de copia de seguridad omiten datos importantes o tu app no puede usar los datos que restablece, los usuarios perderán su configuración y progreso sin ver un error.

Las pruebas automatizadas de copia de seguridad y restablecimiento te ayudan a detectar estos problemas antes de lanzar tu app. Son pruebas de JUnit 5 que se ejecutan en tu máquina de desarrollo y controlan los dispositivos conectados a través de Android Debug Bridge (adb). Cada prueba propaga los datos de la app en un dispositivo, crea una copia de seguridad de la app y la restablece a través del framework de copia de seguridad de Android, y, luego, verifica que los datos estén intactos. Configura las pruebas como un paquete de pruebas del complemento de Android para Gradle (AGP) en el archivo de compilación de tu módulo.

Cómo funciona

Un paquete de pruebas de copia de seguridad y restablecimiento tiene dos partes que funcionan juntas:

  • Las pruebas de host son pruebas de JUnit 5 que se ejecutan en tu máquina de desarrollo. Usan un BackupRestoreController para cada dispositivo con el objetivo de propagar datos, crear copias de seguridad de tu app y restablecerla, y verificar los resultados.
  • Las acciones del dispositivo son clases que implementan BackupDeviceAction. Se ejecutan en el proceso de tu app en el dispositivo, por lo que pueden leer y escribir datos a través del código de tu app. Las pruebas de host llaman a las acciones del dispositivo por nombre de clase.

Cuando ejecutas el paquete, el AGP compila tu app y un APK de prueba que contiene las acciones del dispositivo. El framework de pruebas instala ambos APK en cada dispositivo que usan las pruebas y borra los datos de tu app antes de cada prueba.

Tipos de almacenamiento integrado

En la siguiente tabla, se enumeran las subclases de StorageDomain que te permiten propagar y verificar datos sin escribir acciones en el dispositivo:

Dominio de almacenamiento Datos
StorageDomain.Preference Una clave en un archivo SharedPreferences
StorageDomain.Database Una fila en una tabla de base de datos SQLite.
StorageDomain.TextFile Un archivo de texto en el almacenamiento interno de tu app
StorageDomain.BinaryFile Un archivo binario en el almacenamiento interno de tu app

Para probar otros datos, como los archivos de DataStore, escribe acciones del dispositivo.

Medios de transporte

Cada copia de seguridad usa un valor BackupTransportMode. En la siguiente tabla, se enumeran los modos de transporte admitidos:

Modo Situación
LOCAL Una copia de seguridad en el transporte de copia de seguridad local del dispositivo. Los datos de la copia de seguridad permanecen en el dispositivo.
CLOUD_ENCRYPTED Una copia de seguridad en la nube, como una que se guarda en la Cuenta de Google del usuario desde un dispositivo con encriptación del cliente
CLOUD_UNENCRYPTED Una copia de seguridad en la nube de un dispositivo que no tiene encriptación del cliente
DEVICE_TO_DEVICE Una transferencia de dispositivo a dispositivo, por ejemplo, a través de un cable o Wi-Fi

LOCAL funciona en cualquier dispositivo compatible. Los modos de nube y de dispositivo a dispositivo crean las mismas copias de seguridad que la acción Backup App Data en Android Studio: la copia de seguridad se guarda en tu máquina de desarrollo en lugar de subirse o enviarse a otro dispositivo. Los modos de nube y de dispositivo a dispositivo requieren los Servicios de Google Play en el dispositivo y una compilación depurable de tu app. Si tus reglas de copia de seguridad dependen de la encriptación del cliente, prueba ambos modos de nube.

Requisitos

Para usar las pruebas automatizadas de copia de seguridad y restablecimiento, asegúrate de que tu entorno cumpla con los siguientes requisitos:

  • Gradle 9.6.0 o una versión posterior
  • JDK versión 17 o posterior
  • Un dispositivo o emulador que ejecute Android 12 (nivel de API 31) o una versión posterior, y que esté conectado a través de adb:
    • Los dispositivos o emuladores con el nivel de API 36.1 o posterior requieren la versión 26.33.30 o posterior de los Servicios de Google Play.
    • Para probar las transferencias entre dos dispositivos, conecta dos dispositivos.

Compatibilidad

En la siguiente tabla, se enumeran las versiones mínimas y recomendadas para las pruebas automatizadas de copia de seguridad y restablecimiento:

Componente Versión mínima Versión recomendada
Android Studio Rabbit 2 Canary 1 Rabbit 2 Canary 4 o una versión posterior
Complemento de Android para Gradle (AGP) 9.5.0-alpha06 9.5.0-alpha09 o una versión posterior
androidx.test.backup bibliotecas 1.0.0-alpha01 1.0.0-alpha03 o posterior

Cada versión preliminar del AGP requiere la versión preliminar correspondiente de Android Studio. Para obtener más información, consulta Versiones preliminares del AGP.

Configura tu proyecto

Para agregar un paquete de pruebas de copia de seguridad y restablecimiento al módulo de tu app, completa los siguientes pasos:

Habilita marcas experimentales

En el archivo gradle.properties de tu proyecto, habilita los paquetes de pruebas y las pruebas de copia de seguridad:

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

Declara el paquete de pruebas

En el archivo build.gradle.kts del módulo de tu app, declara un paquete de pruebas de copia de seguridad en el bloque testOptions:

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

El nombre del paquete, backupTest en este ejemplo, determina los directorios del conjunto de orígenes y los nombres de las tareas de Gradle. Puedes personalizar el paquete con las siguientes propiedades opcionales:

  • Usa backupTestLibraryVersion para establecer la versión de las bibliotecas de androidx.test.backup que el AGP agrega al paquete, como "1.0.0-alpha03". Esta propiedad es opcional. Si la omites, AGP recurre a una versión de biblioteca predeterminada según la versión de AGP. Los ejemplos de esta página requieren la versión 1.0.0-alpha03 o una posterior.
  • Usa targetVariants para especificar las variantes de compilación que prueba el paquete, como targetVariants.add("demoDebug"). Esta propiedad es opcional. Si lo omites, el paquete probará las variantes de testBuildType de tu módulo, que es debug de forma predeterminada. Te recomendamos que pruebes una variante depurable, ya que los modos de transporte de nube y de dispositivo a dispositivo requieren una app depurable.

El AGP agrega la biblioteca de host, androidx.test.backup:backup-host y JUnit 5 a las pruebas de host. Agrega la biblioteca de dispositivos, androidx.test.backup:backup, al APK de prueba y configura el ejecutor de instrumentación del APK de prueba.

Para agregar otras dependencias, usa los bloques hostJar y testApk del paquete. Por ejemplo, para usar Truth en tus pruebas de host, agrégala al bloque hostJar:

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

Crea los conjuntos de orígenes

Crea directorios de conjuntos de orígenes que coincidan con el nombre del paquete:

  • Coloca las pruebas del host en src/{suiteName}/test/kotlin/.
  • Coloca las acciones del dispositivo en src/{suiteName}/androidTest/kotlin/.

Por ejemplo, un paquete llamado backupTest usa la siguiente estructura de directorio:

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

Verifica la configuración de la copia de seguridad

Las pruebas crean una copia de seguridad y restablecen los datos que incluye la configuración de copia de seguridad de tu app. Asegúrate de que la copia de seguridad esté habilitada para tu app y que las reglas de copia de seguridad incluyan los datos que pruebes.

Escribe pruebas de copia de seguridad y restablecimiento

Escribe pruebas de host en el conjunto de orígenes test del paquete. Anota cada clase de prueba con @ExtendWith(BackupRestoreExtension::class), que proporciona dispositivos conectados a las pruebas. Las pruebas se ejecutan en la variante de la app a la que se orienta el paquete, por lo que no es necesario que configures su ID de aplicación.

Cada método de prueba declara un parámetro BackupRestoreController para cada dispositivo que usa.

Prueba los tipos de almacenamiento integrados

Para probar los tipos de almacenamiento integrados, llama a runBackupRestoreFlow con los datos que se propagarán, un directorio para el archivo de copia de seguridad y un modo de transporte. El método ejecuta los siguientes pasos en el dispositivo:

  1. Propaga cada dominio de almacenamiento.
  2. Detiene la app.
  3. Crea una copia de seguridad de la app.
  4. Borra los datos de la app.
  5. Restablece la copia de seguridad.
  6. Verifica que cada dominio de almacenamiento tenga el valor semilla.

Si un paso falla, el método arroja una excepción, lo que hace que la prueba falle. En el siguiente ejemplo, se prueban una clave SharedPreferences, una fila de SQLite y un archivo interno con el transporte de copia de seguridad local:

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

Ten en cuenta lo siguiente cuando definas los dominios de almacenamiento:

  • Preference toma el nombre del archivo SharedPreferences sin la extensión .xml.
  • TextFile y BinaryFile resuelven las rutas de acceso relativas en función del filesDir de tu app.
  • Database escribe la fila con SQL y crea la tabla con columnas TEXT si la tabla no existe. Si tu app usa Room, te recomendamos probar el contenido de la base de datos con acciones del dispositivo que usen tus DAO para que la base de datos tenga el esquema que Room espera.

Escribir acciones del dispositivo

Para propagar o verificar datos que no cubren los tipos de almacenamiento integrados, escribe acciones del dispositivo en el conjunto de orígenes androidTest del paquete. Una acción del dispositivo implementa BackupDeviceAction y anula dos miembros:

  • Establece phase en BackupDeviceAction.PHASE_POPULATE para una acción que propaga datos o en BackupDeviceAction.PHASE_VERIFY para una acción que verifica datos.
  • Implementa execute para ejecutar la acción con el Context de tu app y los argumentos de la prueba del host. Muestra un resultado creado con el método de fábrica BackupDeviceActionResult.success o BackupDeviceActionResult.failure, y pasa un mensaje de error a failure.

El método execute se ejecuta en el proceso de tu app en un subproceso en segundo plano, por lo que puede bloquearse hasta que finalicen las operaciones de lectura y escritura.

En el siguiente ejemplo, se inicializa y verifica un parámetro de configuración del tema que la app almacena con Preferences DataStore. La app define el DataStore en su conjunto de orígenes principal:

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

Las acciones del dispositivo usan las mismas definiciones:

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

Para devolver datos a la prueba del host, pasa un mapa al método success. La prueba del host lee el mapa desde BackupActionResult.Success.data.

Ejecuta cada paso del flujo

Para usar acciones del dispositivo o personalizar el flujo, llama a cada paso por tu cuenta. La siguiente prueba de host ejecuta las acciones del dispositivo de la sección anterior en torno a una copia de seguridad y un restablecimiento en la nube:

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

Cuando falla una acción del dispositivo, runOnDevice devuelve un BackupActionResult.Failure en lugar de arrojar una excepción, por lo que debes verificar el resultado. Los otros pasos arrojan una excepción si fallan.

Prueba las transferencias entre dispositivos

Para probar una transferencia entre dos dispositivos, declara un parámetro BackupRestoreController para cada dispositivo. Crea una copia de seguridad de la app en el dispositivo de origen y, luego, restablece el archivo de copia de seguridad en el dispositivo de destino. En el siguiente ejemplo, se reutilizan las constantes y el ayudante assertSuccess del ejemplo anterior:

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

Los valores role de @Device te permiten elegir un dispositivo para cada parámetro cuando ejecutas las pruebas. Si solo hay un dispositivo conectado, ambos parámetros usan ese dispositivo, y la prueba simula la transferencia en un solo dispositivo. Borrar los datos del destino garantiza que los datos restablecidos provengan de la copia de seguridad.

Elegir dispositivos

De forma predeterminada, el framework de pruebas ordena los dispositivos en línea por número de serie y los asigna a los parámetros BackupRestoreController de cada prueba en orden. Si una prueba tiene más parámetros de dispositivo que dispositivos, los parámetros adicionales comparten el primer dispositivo. La variable de entorno ANDROID_SERIAL no afecta la asignación de dispositivos.

Para elegir dispositivos sin colocar números de serie en tus pruebas, asigna un rol a cada parámetro de dispositivo con @Device(role = "..."). Luego, cuando ejecutes las pruebas, vincula cada rol a un dispositivo con la propiedad del sistema androidx.test.backup.device.serial.{role}. Por ejemplo, el siguiente comando ejecuta el paquete con emulator-5554 como dispositivo de origen y emulator-5556 como dispositivo de destino:

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

Una vinculación se aplica solo a los parámetros con ese rol. Otros parámetros obtienen los dispositivos restantes.

También puedes elegir dispositivos con los valores serial y api de @Device, o con las siguientes propiedades del sistema, que tienen prioridad sobre los valores @Device:

Propiedad del sistema Descripción
androidx.test.backup.device.serial.{role} Es el número de serie del dispositivo para los parámetros anotados con @Device(role = "{role}"). Tiene prioridad sobre serials y serial.
androidx.test.backup.device.serials Es una lista separada por comas de números de serie, asignados a los parámetros del dispositivo en orden.
androidx.test.backup.device.serial Es el número de serie del dispositivo para los parámetros que serials no cubre.
androidx.test.backup.device.apis Es una lista separada por comas de niveles de API, asignados a los parámetros del dispositivo en orden.
androidx.test.backup.device.api Es el nivel de API del dispositivo para los parámetros que no cubre apis.

Pasa estas propiedades con -D de la misma manera. Las propiedades serial, serials, api y apis se aplican a cada prueba que se ejecuta, por lo que debes usar la opción --tests para ejecutar solo las pruebas que las necesitan.

Prueba las credenciales de restablecimiento

Si tu app usa Restore Credentials, prueba que su clave de restablecimiento sobreviva a una copia de seguridad y un restablecimiento. Los modos de nube y de dispositivo a dispositivo crean una copia de seguridad de la clave con los datos de tu app, pero LOCAL no lo hace.

Escribir acciones del dispositivo que creen la clave y la obtengan con Credential Manager La acción de creación devuelve el ID de credencial de la clave, de modo que la acción de verificación pueda comprobar que el restablecimiento devuelva la misma clave. En este ejemplo, createRequestJson y getRequestJson son las cadenas JSON de solicitud que tu app pasa al Administrador de credenciales:

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

La siguiente prueba de host crea la clave en el dispositivo de origen, la restablece en el dispositivo de destino y la verifica allí. Usa el asistente assertSuccess de Ejecuta cada paso del flujo:

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

Para crear una clave con isCloudBackupEnabled configurado como true, el valor predeterminado, el dispositivo de origen necesita una Cuenta de Google con la copia de seguridad activada y un bloqueo de pantalla. De lo contrario, el Administrador de credenciales arroja E2eeUnavailableException.

A diferencia de un restablecimiento en la nube en un dispositivo nuevo, los modos de nube no requieren la misma Cuenta de Google ni el bloqueo de pantalla del dispositivo de origen, y restablecen las claves creadas con isCloudBackupEnabled establecido en false.

Conserva los datos de la app entre pruebas

Antes de cada prueba, el framework de pruebas borra los datos de tu app en cada dispositivo que usa la prueba. Para desactivar esta opción en una clase o un método de prueba, anótala con @Isolation(IsolationPolicy.MANUAL).

Escribe pruebas en Java

Los métodos BackupRestoreController son funciones de suspensión de Kotlin. Si escribes pruebas de host en Java, usa la variante Async de cada método, como runBackupRestoreFlowAsync, que devuelve un ListenableFuture.

Ejecuta pruebas de copia de seguridad y restablecimiento

El AGP crea una tarea de Gradle para cada variante que prueba el paquete, llamada test{Variant}{SuiteName}DefaultTestSuite. Para ejecutar el paquete backupTest en la variante debug, conecta tus dispositivos y ejecuta la tarea:

./gradlew :app:testDebugBackupTestDefaultTestSuite

Las tareas check, test y connectedCheck no ejecutan paquetes de pruebas de copia de seguridad y restablecimiento, por lo que debes ejecutar la tarea del paquete de forma explícita.

Para ejecutar una sola clase o un método de prueba, usa la opción --tests:

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

Inspecciona los informes de pruebas

Una vez que se completa una ejecución de prueba, el AGP genera un informe de prueba en formato HTML en {module}/build/reports/tests/{taskName}/index.html, como app/build/reports/tests/testDebugBackupTestDefaultTestSuite/index.html.

Soluciona problemas de restablecimientos con errores

Un restablecimiento de la nube o de dispositivo a dispositivo falla con un mensaje de error en los siguientes casos:

  • Los Servicios de Google Play omiten tu app, por ejemplo, porque su ID de aplicación comienza con com.google. o com.android., su copia de seguridad está vacía o establece android:allowBackup="false". Para probar una app con ese ID de aplicación, usa el modo LOCAL.
  • La versión de los Servicios de Google Play es anterior a la 26.33.30 en un dispositivo o emulador que ejecuta el nivel de API 36.1 o uno posterior. Actualiza los Servicios de Google Play a través de Play Store en el dispositivo o usa una imagen del sistema que incluya la versión 26.33.30 o una posterior.

Problemas conocidos y limitaciones

Las pruebas automatizadas de copia de seguridad y restablecimiento tienen los siguientes problemas conocidos y limitaciones:

  • La compatibilidad de Android Studio con los paquetes de pruebas aún no está disponible. Es posible que el editor de código muestre errores de referencia sin resolver en los archivos fuente del paquete de pruebas, incluso cuando el proyecto esté configurado correctamente. En su lugar, compila y ejecuta pruebas de copia de seguridad y restablecimiento desde la línea de comandos con Gradle.
  • Las pruebas se ejecutan solo en dispositivos y emuladores que están conectados a tu máquina de desarrollo a través de adb. No se admite Firebase Test Lab.
  • Las pruebas borran los datos de tu app y cambian la configuración de la copia de seguridad en los dispositivos que usan. Te recomendamos que uses dispositivos de prueba exclusivos.

Para conocer los cambios en cada versión, consulta las notas de la versión de prueba de copia de seguridad y restablecimiento.