Automatisierte Sicherungs- und Wiederherstellungstests

Wenn Nutzer ein neues Gerät einrichten oder Ihre App neu installieren, kann Android die Daten Ihrer App aus einer Cloud-Sicherung oder über eine Gerät-zu-Gerät-Übertragung wiederherstellen. Wenn in Ihren Sicherungsregeln wichtige Daten fehlen oder Ihre App die wiederhergestellten Daten nicht verwenden kann, verlieren Nutzer ihre Einstellungen und ihren Fortschritt, ohne dass eine Fehlermeldung angezeigt wird.

Mit automatisierten Tests zum Sichern und Wiederherstellen können Sie diese Probleme erkennen, bevor Sie Ihre App veröffentlichen. Es handelt sich um JUnit 5-Tests, die auf Ihrem Entwicklungscomputer ausgeführt werden und verbundene Geräte über die Android Debug Bridge (adb) steuern. Bei jedem Test werden App-Daten auf einem Gerät bereitgestellt, die App wird über das Android-Sicherungsframework gesichert und wiederhergestellt und dann wird geprüft, ob die Daten intakt sind. Sie konfigurieren die Tests als Android-Gradle-Plug-in-Testsuite (AGP) Testsuite in der Build-Datei Ihres Moduls.

Funktionsweise

Eine Testsuite zum Sichern und Wiederherstellen besteht aus zwei Teilen, die zusammenarbeiten:

  • Hosttests sind JUnit 5-Tests, die auf Ihrem Entwicklungscomputer ausgeführt werden. Sie verwenden für jedes Gerät einen BackupRestoreController, um Daten bereitzustellen, Ihre App zu sichern und wiederherzustellen und die Ergebnisse zu prüfen.
  • Geräteaktionen sind Klassen, die BackupDeviceAction implementieren. Sie werden im Prozess Ihrer App auf dem Gerät ausgeführt, sodass sie Daten über den eigenen Code Ihrer App lesen und schreiben können. Hosttests rufen Geräteaktionen über den Klassennamen auf.

Wenn Sie die Suite ausführen, erstellt AGP Ihre App und ein Test-APK, das Ihre Geräteaktionen enthält. Vor jedem Test installiert das Testframework beide APKs auf jedem Gerät, das der Test verwendet, und löscht dann die Daten Ihrer App.

Integrierte Speichertypen

In der folgenden Tabelle sind die StorageDomain-Unterklassen aufgeführt, mit denen Sie Daten bereitstellen und prüfen können, ohne Geräteaktionen schreiben zu müssen:

Speicherdomain Daten
StorageDomain.Preference Ein Schlüssel in einer SharedPreferences-Datei.
StorageDomain.Database Eine Zeile in einer SQLite-Datenbanktabelle.
StorageDomain.TextFile Eine Textdatei im internen Speicher Ihrer App.
StorageDomain.BinaryFile Eine Binärdatei im internen Speicher Ihrer App.

Wenn Sie andere Daten wie DataStore-Dateien testen möchten, schreiben Sie Geräte aktionen.

Übertragungsmodi

Für jede Sicherung wird ein BackupTransportMode-Wert verwendet. In der folgenden Tabelle sind die unterstützten Übertragungsmodi aufgeführt:

Modus Szenario
LOCAL Eine Sicherung auf dem lokalen Sicherungstransport des Geräts. Die Sicherungsdaten bleiben auf dem Gerät.
CLOUD_ENCRYPTED Eine Cloud-Sicherung, z. B. eine Sicherung, die auf dem Google-Konto des Nutzers von einem Gerät mit clientseitiger Verschlüsselung gespeichert wurde.
CLOUD_UNENCRYPTED Eine Cloud-Sicherung von einem Gerät ohne clientseitige Verschlüsselung.
DEVICE_TO_DEVICE Eine Gerät-zu-Gerät-Übertragung, z. B. über ein Kabel oder WLAN.

LOCAL funktioniert auf jedem unterstützten Gerät. In den Modi „Cloud“ und „Gerät-zu-Gerät“ werden dieselben Sicherungen wie bei der Aktion App-Daten sichern in Android Studio erstellt. Die Sicherung wird auf Ihrem Entwicklungscomputer gespeichert, anstatt hochgeladen oder an ein anderes Gerät gesendet zu werden. Für die Modi „Cloud“ und „Gerät-zu-Gerät“ sind Google Play-Dienste auf dem Gerät und ein debugfähiger Build Ihrer App erforderlich. Wenn Ihre Sicherungsregeln von der clientseitigen Verschlüsselung abhängen, testen Sie beide Cloud-Modi.

Voraussetzungen

Damit Sie automatisierte Tests zum Sichern und Wiederherstellen verwenden können, muss Ihre Umgebung die folgenden Voraussetzungen erfüllen:

  • Gradle-Version 9.6.0 oder höher.
  • JDK-Version 17 oder höher.
  • Ein Gerät oder Emulator mit Android 12 (API-Level 31) oder höher, das über adb verbunden ist. Wenn Sie Übertragungen zwischen zwei Geräten testen möchten, verbinden Sie zwei Geräte.

Kompatibilität

In der folgenden Tabelle sind die Mindest- und empfohlenen Versionen für automatisierte Tests zum Sichern und Wiederherstellen aufgeführt:

Komponente Mindestversion Empfohlene Version
Android Studio Rabbit 2 Canary 1 Rabbit 2 Canary 4 oder höher
Android-Gradle-Plug-in (AGP) 9.5.0-alpha06 9.5.0-alpha09 oder höher
androidx.test.backup-Bibliotheken 1.0.0-alpha01 1.0.0-alpha02 oder höher

Für jede Vorabversion von AGP ist die entsprechende Vorabversion von Android Studio erforderlich. Weitere Informationen finden Sie unter AGP-Vorabversionen.

Projekt einrichten

So fügen Sie Ihrem App-Modul eine Test-Suite zum Sichern und Wiederherstellen hinzu:

Experimentelle Flags aktivieren

Aktivieren Sie in der Datei gradle.properties Ihres Projekts Testsuites und Sicherungstests:

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

Test-Suite deklarieren

Deklarieren Sie in der Datei build.gradle.kts Ihres App-Moduls eine Backup-Test-Suite im Block testOptions:

android {
    testOptions {
        backupTests {
            create("backupTest")
        }
    }
}

Der Name der Suite, in diesem Beispiel backupTest, bestimmt die Source-Set-Verzeichnisse und die Namen der Gradle-Aufgaben. Sie können die Suite mit den folgenden optionalen Attributen anpassen:

  • Verwenden Sie backupTestLibraryVersion, um die Version der androidx.test.backup Bibliotheken festzulegen, die AGP der Suite hinzufügt, z. B. "1.0.0-alpha02". Dieses Attribut ist optional. Wenn Sie es weglassen, greift AGP auf eine Standardbibliotheksversion basierend auf der AGP-Version zurück.
  • Verwenden Sie targetVariants, um die Build-Varianten anzugeben, die mit der Suite getestet werden, z. B. targetVariants.add("demoDebug"). Dieses Attribut ist optional. Wenn Sie es weglassen, testet die Suite die Varianten von testBuildType Ihres Moduls, das standardmäßig debug ist. Wir empfehlen, eine debugfähige Variante zu testen, da für die Übertragungsmodi „Cloud“ und „Gerät-zu-Gerät“ eine debugfähige App erforderlich ist.

AGP fügt den Hosttests die Hostbibliothek androidx.test.backup:backup-host und JUnit 5 hinzu. Es fügt dem Test-APK die Gerätebibliothek androidx.test.backup:backup hinzu und legt den Instrumentierungs-Runner des Test-APKs fest.

Verwenden Sie die Blöcke hostJar und testApk der Suite, um weitere Abhängigkeiten hinzuzufügen. Wenn Sie beispielsweise Truth in Ihren Hosttests verwenden möchten, fügen Sie es dem hostJar Block hinzu:

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

Source-Sets erstellen

Erstellen Sie Source-Set-Verzeichnisse, die dem Namen der Suite entsprechen:

  • Hosttests in src/{suiteName}/test/kotlin/ platzieren.
  • Geräteaktionen in src/{suiteName}/androidTest/kotlin/ platzieren.

Für eine Suite mit dem Namen backupTest wird beispielsweise die folgende Verzeichnisstruktur verwendet:

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

Sicherungskonfiguration prüfen

Bei Tests werden die Daten gesichert und wiederhergestellt, die in der Sicherungskonfiguration Ihrer App enthalten sind. Achten Sie darauf, dass die Sicherung für Ihre App aktiviert ist und dass Ihre Sicherungsregeln die Daten enthalten, die Sie testen.

Tests zum Sichern und Wiederherstellen schreiben

Schreiben Sie Hosttests im Quellsatz test der Suite. Jede Testklasse benötigt zwei Anmerkungen:

  • @ExtendWith(BackupRestoreExtension::class) stellt den Tests verbundene Geräte zur Verfügung.
  • @BackupRestoreConfig(applicationId = "...") legt die Anwendungs-ID von der zu testenden App fest. Verwenden Sie die Anwendungs-ID der Variante, die Sie testen, einschließlich aller applicationIdSuffix.

Jede Testmethode deklariert einen BackupRestoreController-Parameter für jedes Gerät, das sie verwendet.

Integrierte Speichertypen testen

Wenn Sie integrierte Speichertypen testen möchten, rufen Sie runBackupRestoreFlow mit den zu bereitstellenden Daten, einem Verzeichnis für die Sicherungsdatei und einem Übertragungsmodus auf. Die Methode führt die folgenden Schritte auf dem Gerät aus:

  1. Jede Speicherdomain wird bereitgestellt.
  2. Die App wird beendet.
  3. Die App wird gesichert.
  4. Die Daten der App werden gelöscht.
  5. Die Sicherung wird wiederhergestellt.
  6. Es wird geprüft, ob jede Speicherdomain den bereitgestellten Wert hat.

Wenn ein Schritt fehlschlägt, löst die Methode eine Ausnahme aus, wodurch der Test fehlschlägt. Im folgenden Beispiel werden ein SharedPreferences-Schlüssel, eine SQLite-Zeile und eine interne Datei mit dem lokalen Sicherungstransport getestet:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreConfig
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)
@BackupRestoreConfig(applicationId = "com.example.myapp")
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,
        )
    }
}

Beachten Sie beim Definieren von Speicherdomains Folgendes:

  • Preference verwendet den Namen der SharedPreferences-Datei ohne die .xml Erweiterung.
  • TextFile und BinaryFile lösen relative Pfade in Bezug auf filesDir Ihrer App auf.
  • Database schreibt die Zeile mit SQL und erstellt die Tabelle mit TEXT-Spalten, wenn sie nicht vorhanden ist. Wenn Ihre App Room verwendet, empfehlen wir, Datenbankinhalte mit Geräteaktionen zu testen, die Ihre DAOs verwenden, damit die Datenbank das von Room erwartete Schema hat.

Geräteaktionen schreiben

Wenn Sie Daten bereitstellen oder prüfen möchten, die nicht von den integrierten Speichertypen abgedeckt werden, schreiben Sie Geräteaktionen im Quellsatz androidTest der Suite. Eine Geräteaktion implementiert BackupDeviceAction und überschreibt zwei Elemente:

  • Legen Sie phase auf BackupDeviceAction.PHASE_POPULATE für eine Aktion fest, die Daten bereitstellt, oder auf BackupDeviceAction.PHASE_VERIFY für eine Aktion, die Daten prüft.
  • Implementieren Sie execute, um die Aktion mit dem Context Ihrer App und den Argumenten aus dem Hosttest auszuführen. Geben Sie ein Ergebnis zurück, das mit der BackupDeviceActionResult.success oder BackupDeviceActionResult.failure Factory-Methode erstellt wurde, und übergeben Sie eine Fehlermeldung an failure.

Die Methode execute wird im Prozess Ihrer App in einem Hintergrundthread ausgeführt, sodass sie blockiert werden kann, bis Lese- und Schreibvorgänge abgeschlossen sind.

Im folgenden Beispiel wird eine Theme-Einstellung bereitgestellt und geprüft, die die App mit Preferences DataStore speichert. mit Preferences DataStore. Die App definiert den DataStore in ihrem Haupt-Source-Set:

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

Die Geräteaktionen verwenden dieselben Definitionen:

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

Wenn Sie Daten an den Hosttest zurückgeben möchten, übergeben Sie eine Map an die Methode success. Der Hosttest liest die Map aus BackupActionResult.Success.data.

Jeden Schritt des Ablaufs ausführen

Wenn Sie Geräteaktionen verwenden oder den Ablauf anpassen möchten, rufen Sie jeden Schritt selbst auf. Der folgende Hosttest führt die Geräteaktionen aus dem vorherigen Abschnitt für eine Cloud-Sicherung und ‑Wiederherstellung aus:

package com.example.myapp

import androidx.test.backup.host.BackupActionResult
import androidx.test.backup.host.BackupRestoreConfig
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)
@BackupRestoreConfig(applicationId = "com.example.myapp")
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)
}

Wenn eine Geräteaktion fehlschlägt, gibt runOnDevice ein BackupActionResult.Failure zurück, anstatt eine Ausnahme auszulösen, prüfen Sie daher das Ergebnis. Die anderen Schritte lösen eine Ausnahme aus, wenn sie fehlschlagen.

Übertragungen zwischen Geräten testen

Wenn Sie eine Übertragung zwischen zwei Geräten testen möchten, deklarieren Sie für jedes Gerät einen BackupRestoreController-Parameter. Sichern Sie die App auf dem Quellgerät und stellen Sie dann die Sicherungsdatei auf dem Zielgerät wieder her. Im folgenden Beispiel werden die Konstanten und der assertSuccess-Helfer aus dem vorherigen Beispiel wiederverwendet:

package com.example.myapp

import androidx.test.backup.host.BackupRestoreConfig
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)
@BackupRestoreConfig(applicationId = "com.example.myapp")
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()
    }
}

Der Wert role von @Device ist ein Label, das den Test leichter lesbar macht. Er hat keine Auswirkungen darauf, welches Gerät einem Parameter zugewiesen wird. Wenn nur ein Gerät verbunden ist, verwenden beide Parameter dieses Gerät und der Test simuliert die Übertragung auf einem einzelnen Gerät. Durch das Löschen der Daten des Zielgeräts wird sichergestellt, dass die wiederhergestellten Daten aus der Sicherung stammen.

Geräte auswählen

Standardmäßig sortiert das Testframework die Onlinegeräte nach Seriennummer und weist sie den BackupRestoreController-Parametern nach Position zu. Der erste Parameter der Testmethode erhält beispielsweise das erste Gerät und der zweite Parameter das zweite Gerät. Wenn für eine Position kein Gerät vorhanden ist, erhält der Parameter das erste Gerät. Bei den Positionen werden alle Parameter der Methode berücksichtigt. Deklarieren Sie daher Geräteparameter vor anderen Parametern wie @TempDir. Die Umgebungsvariable ANDROID_SERIAL hat keine Auswirkungen auf die Gerätezuweisung.

Wenn Sie Geräte auswählen möchten, legen Sie die Werte serial oder api von @Device fest oder legen Sie JVM-Systemeigenschaften fest. Systemeigenschaften haben Vorrang vor @Device-Werten. In der folgenden Tabelle sind die unterstützten Systemeigenschaften aufgeführt:

Systemeigenschaft Beschreibung
androidx.test.backup.device.serial Die Seriennummer des Geräts für alle Geräteparameter.
androidx.test.backup.device.serials Eine durch Kommas getrennte Liste von Seriennummern, die den Parametern nach Position zugewiesen werden.
androidx.test.backup.device.serial.{name} Die Seriennummer für Parameter, die mit @Device(serial = "{name}") annotiert sind.
androidx.test.backup.device.api Das API-Level des Geräts für alle Geräteparameter.
androidx.test.backup.device.apis Eine durch Kommas getrennte Liste von API-Levels, die den Parametern nach Position zugewiesen werden.

Übergeben Sie diese Eigenschaften mit -D, wenn Sie die Tests über die Befehlszeile ausführen. Die Eigenschaften gelten für jeden Test, der ausgeführt wird. Verwenden Sie daher die Option --tests, um nur die Tests auszuführen, für die sie erforderlich sind. Mit dem folgenden Befehl wird beispielsweise ThemeTransferTest mit emulator-5554 als Quellgerät und emulator-5556 als Zielgerät ausgeführt:

./gradlew :app:testDebugBackupTestDefaultTestSuite --tests "com.example.myapp.ThemeTransferTest" -Dandroidx.test.backup.device.serials=emulator-5554,emulator-5556

App-Daten zwischen Tests beibehalten

Vor jedem Test löscht das Testframework die Daten Ihrer App auf jedem Gerät, das der Test verwendet. Wenn Sie dies für eine Testklasse oder -methode deaktivieren möchten, annotieren Sie sie mit @Isolation(IsolationPolicy.MANUAL).

Tests in Java schreiben

BackupRestoreController-Methoden sind Kotlin-Suspend-Funktionen. Wenn Sie Hosttests in Java schreiben, verwenden Sie die Async Variante jeder Methode, z. B. runBackupRestoreFlowAsync, die ein ListenableFuture zurückgibt.

Tests zum Sichern und Wiederherstellen ausführen

AGP erstellt für jede Variante, die mit der Suite getestet wird, eine Gradle-Aufgabe mit dem Namen test{Variant}{SuiteName}DefaultTestSuite. Wenn Sie die Suite backupTest für die Variante debug ausführen möchten, verbinden Sie Ihre Geräte und führen Sie die Aufgabe aus:

./gradlew :app:testDebugBackupTestDefaultTestSuite

Die Aufgaben check, test und connectedCheck führen keine Testsuites zum Sichern und Wiederherstellen aus. Führen Sie daher die Aufgabe der Suite explizit aus.

Wenn Sie eine einzelne Testklasse oder ‑methode ausführen möchten, verwenden Sie die --tests Option:

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

Testberichte prüfen

Nach Abschluss eines Testlaufs generiert AGP einen HTML-Testbericht unter {module}/build/reports/tests/{taskName}/index.html, z. B. app/build/reports/tests/testDebugBackupTestDefaultTestSuite/index.html.

Bekannte Probleme und Beschränkungen

Für automatisierte Tests zum Sichern und Wiederherstellen gelten die folgenden bekannten Probleme und Beschränkungen:

  • Die Unterstützung für Testsuites in Android Studio ist noch nicht verfügbar. Der Code-Editor zeigt möglicherweise Fehler für nicht aufgelöste Verweise in den Quellcode-Dateien der Testsuite an, auch wenn Ihr Projekt richtig konfiguriert ist. Erstellen und führen Sie stattdessen Tests zum Sichern und Wiederherstellen über die Befehlszeile mit Gradle aus.
  • Tests werden nur auf Geräten und Emulatoren ausgeführt, die über adb mit Ihrem Entwicklungscomputer verbunden sind. Firebase Test Lab wird nicht unterstützt.
  • Bei Tests werden die Daten Ihrer App gelöscht und die Sicherungseinstellungen auf den verwendeten Geräten geändert. Wir empfehlen, dedizierte Testgeräte zu verwenden.

Informationen zu Änderungen in den einzelnen Releases finden Sie in den Versionshinweisen zu Tests zum Sichern und Wiederherstellen.