Bibliotheken und Tools zum Testen verschiedener Bildschirmgrößen

Android bietet eine Vielzahl von Tools und APIs, mit denen Sie Tests für Bildschirm- und Fenstergrößen verändert werden kann.

DeviceConfigurationOverride

Mit der zusammensetzbaren Funktion DeviceConfigurationOverride können Sie Konfigurationsattribute zum Testen mehrerer Bildschirm- und Fenstergrößen in „Compose“ Layouts. Die Überschreibung ForcedSize passt in jedes Layout im verfügbaren Bereich. mit dem Sie beliebige UI-Test für alle Bildschirmgrößen Sie können beispielsweise einen kleinen Smartphone-Formfaktor um alle UI-Tests auszuführen, einschließlich UI-Tests für große Smartphones, faltbare Tablets.

   DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
<ph type="x-smartling-placeholder">
</ph>
Abbildung 1. Verwenden von DeviceConfigurationOverride, um ein Tablet-Layout in ein Gerät mit einem kleineren Formfaktor anzupassen, wie in \*Now in Android*.

Außerdem können Sie mit dieser zusammensetzbaren Funktion Schriftgröße, Designs und andere und Eigenschaften, die Sie an verschiedenen Fenstergrößen testen können.

Robolektrik

Verwenden Sie Robolectric, um Compose- oder ansichtsbasierte UI-Tests auf der JVM auszuführen. lokal – keine Geräte oder Emulatoren erforderlich. Sie können die Konfiguration Robotik zur Verwendung bestimmter Bildschirmgrößen sowie weitere nützliche Eigenschaften.

Im folgenden Beispiel von Now in Android ist Robolectric wie folgt konfiguriert: , um eine Bildschirmgröße von 1.000 x 1.000 dp und eine Auflösung von 480 dpi zu emulieren:

@RunWith(RobolectricTestRunner::class)
// Configure Robolectric to use a very large screen size that can fit all of the test sizes.
// This allows enough room to render the content under test without clipping or scaling.
@Config(qualifiers = "w1000dp-h1000dp-480dpi")
class NiaAppScreenSizesScreenshotTests { ... }

Sie können die Kennzeichner auch über den Testtext festlegen, wie in diesem Snippet aus dem Beispiel Now in Android:

val (width, height, dpi) = ...

// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")

Beachten Sie, dass RuntimeEnvironment.setQualifiers() das System und die Anwendungsressourcen mit der neuen Konfiguration, die jedoch keine Aktion auslösen für aktive Aktivitäten oder andere Komponenten.

Weitere Informationen finden Sie in der Dokumentation zur Gerätekonfiguration von Robolectric.

Von Gradle verwaltete Geräte

Das Android-Gradle-Plug-in Gradle-managed devices (GMD) die Spezifikationen der Emulatoren und realen Geräte definieren, Ihre instrumentierten Tests ausführen. Erstellen Sie Spezifikationen für Geräte mit Bildschirmgrößen, um eine Teststrategie zu implementieren, bei der bestimmte Tests für bestimmte Bildschirmgrößen aus. Durch die Verwendung von GMD mit Continuous Integration (CI) können Sie sicherstellen, dass bei Bedarf die entsprechenden Tests ausgeführt werden. Bereitstellen und Starten von Emulatoren und Vereinfachen der CI-Einrichtung

android {
    testOptions {
        managedDevices {
            devices {
                // Run with ./gradlew nexusOneApi30DebugAndroidTest.
                nexusOneApi30(com.android.build.api.dsl.ManagedVirtualDevice) {
                    device = "Nexus One"
                    apiLevel = 30
                    // Use the AOSP ATD image for better emulator performance
                    systemImageSource = "aosp-atd"
                }
                // Run with ./gradlew  foldApi34DebugAndroidTest.
                foldApi34(com.android.build.api.dsl.ManagedVirtualDevice) {
                    device = "Pixel Fold"
                    apiLevel = 34
                    systemImageSource = "aosp-atd"
                }
            }
        }
    }
}

Im Projekt testing-samples finden Sie mehrere GMD-Beispiele.

Firebase Test Lab

Verwende Firebase Test Lab (FTL) oder einen ähnlichen Device Farm-Dienst, um deine Tests auf bestimmten realen Geräten durchführen, auf die Sie möglicherweise keinen Zugriff haben, z. B. faltbare Smartphones oder Tablets unterschiedlicher Größe. Firebase Test Lab ist ein kostenpflichtiges kostenlosen Dienst verfügbar ist. FTL unterstützt auch das Ausführen von Tests auf Emulatoren. Diese Dienste verbessern die Zuverlässigkeit und Geschwindigkeit von instrumentierten Tests, Geräte und Emulatoren im Voraus bereitstellen können.

Informationen zur Verwendung von FTL mit GMD finden Sie unter Tests skalieren mit Von Gradle verwaltete Geräte.

Filterung mit dem Test-Runner testen

Eine optimale Teststrategie sollte nicht dasselbe Ergebnis zweimal überprüfen. Die meisten Ihrer UI-Tests müssen nicht auf mehreren Geräten ausgeführt werden. Normalerweise filtern Sie alle oder die meisten davon auf einem Smartphone-Formfaktor und nur einen Teil mit unterschiedlichen Bildschirmgrößen.

Sie können bestimmte Tests so annotieren, dass sie nur mit bestimmten Geräten ausgeführt werden, und sie dann bestanden haben. ein Argument an AndroidJUnitRunner mit dem Befehl, der die Tests durchführen.

Du kannst beispielsweise verschiedene Anmerkungen erstellen:

annotation class TestExpandedWidth
annotation class TestCompactWidth

Und verwenden Sie sie in verschiedenen Tests:

class MyTestClass {

    @Test
    @TestExpandedWidth
    fun myExample_worksOnTablet() {
        ...
    }

    @Test
    @TestCompactWidth
    fun myExample_worksOnPortraitPhone() {
        ...
    }

}

Sie können dann den android.testInstrumentationRunnerArguments.annotation verwenden. wenn Sie die Tests ausführen, um bestimmte zu filtern. Wenn Sie zum Beispiel mit Gradle-verwalteten Geräten:

$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'

Wenn Sie GMD nicht verwenden und Emulatoren auf CI verwalten, stellen Sie zuerst sicher, dass die wenn der Emulator oder das Gerät bereit und verbunden ist, und übergeben Sie dann den Parameter zu einem der Gradle-Befehle hinzufügen, um instrumentierte Tests auszuführen:

$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'

Beachten Sie, dass das Espresso-Gerät (siehe nächster Abschnitt) auch Tests mithilfe von Geräteeigenschaften.

Espressogerät

Verwenden Sie Espresso Device, um Aktionen auf Emulatoren in Tests mit beliebigen Art von instrumentierten Tests, einschließlich Espresso-, Compose- oder UI Automator-Tests. Sie können beispielsweise die Bildschirmgröße einstellen oder den Status von faltbaren Smartphones umschalten. oder Postures. Sie können beispielsweise einen Emulator für faltbare Smartphones steuern und ihn auf Modus „Auf dem Tisch“. Espresso Device enthält auch JUnit-Regeln und Anmerkungen, erfordern bestimmte Funktionen:

@RunWith(AndroidJUnit4::class)
class OnDeviceTest {

    @get:Rule(order=1) val activityScenarioRule = activityScenarioRule<MainActivity>()

    @get:Rule(order=2) val screenOrientationRule: ScreenOrientationRule =
        ScreenOrientationRule(ScreenOrientation.PORTRAIT)

    @Test
    fun tabletopMode_playerIsDisplayed() {
        // Set the device to tabletop mode.
        onDevice().setTabletopMode()
        onView(withId(R.id.player)).check(matches(isDisplayed()))
    }
}

Beachten Sie, dass sich Espresso Device noch in der Alphaphase befindet und folgende Voraussetzungen erfüllt: Anforderungen:

  • Android-Gradle-Plug-in 8.3 oder höher
  • Android Emulator 33.1.10 oder höher
  • Virtuelles Android-Gerät mit API-Level 24 oder höher

Tests filtern

Espresso Device kann die Eigenschaften verbundener Geräte lesen, damit Sie Folgendes tun können: Filtern von Tests mithilfe von Annotationen. Wenn die angegebenen Anforderungen nicht erfüllt sind, werden die Tests übersprungen.

ErfordertDeviceMode-Annotation

Die Annotation RequiresDeviceMode kann mehrfach verwendet werden, um anzugeben, einen Test, der nur ausgeführt wird, wenn alle DeviceMode-Werte unterstützt werden auf dem Gerät.

class OnDeviceTest {
    ...
    @Test
    @RequiresDeviceMode(TABLETOP)
    @RequiresDeviceMode(BOOK)
    fun tabletopMode_playerIdDisplayed() {
        // Set the device to tabletop mode.
        onDevice().setTabletopMode()
        onView(withId(R.id.player)).check(matches(isDisplayed()))
    }
}

ErfordertDisplay-Anmerkung

Mit der Anmerkung RequiresDisplay können Sie die Breite und Höhe der des Gerätebildschirms mithilfe von Größenklassen, die Dimensionsgruppen definieren gemäß den offiziellen Fenstergrößenklassen.

class OnDeviceTest {
    ...
    @Test
    @RequiresDisplay(EXPANDED, COMPACT)
    fun myScreen_expandedWidthCompactHeight() {
        ...
    }
}

Größe von Bildschirmen anpassen

Verwenden Sie die Methode setDisplaySize(), um die Größe des Bildschirms anzupassen. während der Laufzeit. Die Methode in Verbindung mit DisplaySizeRule verwenden -Klasse, mit der sichergestellt wird, dass während der Tests vorgenommene Änderungen vor der für den nächsten Test.

@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {

    @get:Rule(order = 1) val activityScenarioRule = activityScenarioRule<MainActivity>()

    // Test rule for restoring device to its starting display size when a test case finishes.
    @get:Rule(order = 2) val displaySizeRule: DisplaySizeRule = DisplaySizeRule()

    @Test
    fun resizeWindow_compact() {
        onDevice().setDisplaySize(
            widthSizeClass = WidthSizeClass.COMPACT,
            heightSizeClass = HeightSizeClass.COMPACT
        )
        // Verify visual attributes or state restoration.
    }
}

Wenn Sie die Größe einer Anzeige mit setDisplaySize() ändern, wirkt sich das nicht auf die Kompaktheitsgrad aus Das heißt, wenn eine Dimension nicht in das Zielgerät passt, schlägt mit einem UnsupportedDeviceOperationException fehl. Um zu verhindern, dass Tests filtern Sie sie mit der Annotation RequiresDisplay heraus:

@RunWith(AndroidJUnit4::class)
class ResizeDisplayTest {

    @get:Rule(order = 1) var activityScenarioRule = activityScenarioRule<MainActivity>()

    // Test rule for restoring device to its starting display size when a test case finishes.
    @get:Rule(order = 2) var displaySizeRule: DisplaySizeRule = DisplaySizeRule()

    /**
     * Setting the display size to EXPANDED would fail in small devices, so the [RequiresDisplay]
     * annotation prevents this test from being run on devices outside the EXPANDED buckets.
     */
    @RequiresDisplay(
        widthSizeClass = WidthSizeClassEnum.EXPANDED,
        heightSizeClass = HeightSizeClassEnum.EXPANDED
    )
    @Test
    fun resizeWindow_expanded() {
        onDevice().setDisplaySize(
            widthSizeClass = WidthSizeClass.EXPANDED,
            heightSizeClass = HeightSizeClass.EXPANDED
        )
        // Verify visual attributes or state restoration.
    }
}

StateRestorationTester

Die Klasse StateRestorationTester wird zum Testen der Statuswiederherstellung verwendet für zusammensetzbare Komponenten an, ohne die Aktivitäten neu zu erstellen. Dadurch werden Tests schneller und zuverlässiger, da die Erholung von Freizeitaktivitäten ein komplexer Prozess mit vielen Synchronisierungsmechanismen:

@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
    val stateRestorationTester = StateRestorationTester(composeTestRule)

    // Set content through the StateRestorationTester object.
    stateRestorationTester.setContent {
        MyApp()
    }

    // Simulate a config change.
    stateRestorationTester.emulateSavedInstanceStateRestore()
}

Fenstertestbibliothek

Die Window Testing-Bibliothek enthält Dienstprogramme, mit denen Sie Tests schreiben können, Funktionen zur Fensterverwaltung aktivieren oder überprüfen, z. B. Aktivitäten oder faltbare Funktionen. Das Artefakt ist über das Google-Tool Maven-Repository.

Sie können beispielsweise die Funktion FoldingFeature() verwenden, um ein benutzerdefinierte FoldingFeature-Datei, die Sie in der Vorschau für das Schreiben verwenden können. In Java verwenden Sie die Funktion createFoldingFeature().

In einer Vorschau vom Typ „Schreiben“ können Sie FoldingFeature so implementieren:

@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
    MyApplicationTheme {
        ExampleScreen(
            displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
        )
 }

Außerdem können Sie Anzeigefunktionen in UI-Tests emulieren, indem Sie die TestWindowLayoutInfo()-Funktion. Im folgenden Beispiel wird ein FoldingFeature mit einem HALF_OPENED in der Bildschirmmitte vertikal und prüft dann, zu erwarten ist:

Schreiben

import androidx.window.layout.FoldingFeature.Orientation.Companion.VERTICAL
import androidx.window.layout.FoldingFeature.State.Companion.HALF_OPENED
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule

@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {

    @get:Rule(order=1)
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @get:Rule(order=2)
    val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()

    @Test
    fun foldedWithHinge_foldableUiDisplayed() {
        composeTestRule.setContent {
            MediaPlayerScreen()
        }

        val hinge = FoldingFeature(
            activity = composeTestRule.activity,
            state = HALF_OPENED,
            orientation = VERTICAL,
            size = 2
        )

        val expected = TestWindowLayoutInfo(listOf(hinge))
        windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)

        composeTestRule.waitForIdle()

        // Verify that the folding feature is detected and media controls shown.
        composeTestRule.onNodeWithTag("MEDIA_CONTROLS").assertExists()
    }
}

Aufrufe

import androidx.window.layout.FoldingFeature.Orientation
import androidx.window.layout.FoldingFeature.State
import androidx.window.testing.layout.FoldingFeature
import androidx.window.testing.layout.TestWindowLayoutInfo
import androidx.window.testing.layout.WindowLayoutInfoPublisherRule

@RunWith(AndroidJUnit4::class)
class MediaControlsFoldingFeatureTest {

    @get:Rule(order=1)
    val activityRule = ActivityScenarioRule(MediaPlayerActivity::class.java)

    @get:Rule(order=2)
    val windowLayoutInfoPublisherRule = WindowLayoutInfoPublisherRule()

    @Test
    fun foldedWithHinge_foldableUiDisplayed() {
        activityRule.scenario.onActivity { activity ->
            val feature = FoldingFeature(
                activity = activity,
                state = State.HALF_OPENED,
                orientation = Orientation.VERTICAL)
            val expected = TestWindowLayoutInfo(listOf(feature))
            windowLayoutInfoPublisherRule.overrideWindowLayoutInfo(expected)
        }

        // Verify that the folding feature is detected and media controls shown.
        onView(withId(R.id.media_controls)).check(matches(isDisplayed()))
    }
}

Weitere Beispiele finden Sie im WindowManager-Projekt.

Weitere Informationen

Dokumentation

Produktproben

Codelabs