Android bietet eine Vielzahl von Tools und APIs, mit denen Sie Tests für verschiedene Bildschirm- und Fenstergrößen erstellen können.
DeviceConfigurationOverride
Mit der DeviceConfigurationOverride komponierbaren Funktion können Sie Konfigurationsattribute überschreiben, um mehrere Bildschirm- und Fenstergrößen in Compose-Layouts zu testen. Die ForcedSize Überschreibung passt jedes Layout an den verfügbaren Platz an,
so können Sie jeden
UI-Test auf jeder Bildschirmgröße ausführen. Sie können beispielsweise einen kleinen Smartphone-Formfaktor verwenden, um alle UI-Tests auszuführen, einschließlich UI-Tests für große Smartphones, faltbare Geräte und Tablets.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}
Außerdem können Sie mit dieser zusammensetzbaren Funktion die Schriftgröße, Designs und andere Eigenschaften festlegen, die Sie auf verschiedenen Fenstergrößen testen möchten.
Robolectric
Mit Robolectric können Sie Compose- oder ansichtsbasierte UI-Tests lokal auf der JVM ausführen. Geräte oder Emulatoren sind nicht erforderlich. Sie können Robolectric so konfigurieren , dass bestimmte Bildschirmgrößen verwendet werden, und weitere nützliche Eigenschaften festlegen.
Im folgenden Beispiel aus Now in Android ist Robolectric so konfiguriert, dass eine Bildschirmgröße von 1000 × 1000 dp mit einer Auflösung von 480 dpi emuliert wird:
@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 Qualifizierer auch aus dem Testkörper festlegen, wie in diesem Snippet aus dem Now in Android-Beispiel:
val (width, height, dpi) = ...
// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")
Hinweis: RuntimeEnvironment.setQualifiers() aktualisiert die System- und App-Ressourcen mit der neuen Konfiguration, löst aber keine Aktion für aktive Aktivitäten oder andere Komponenten aus.
Weitere Informationen finden Sie in der Dokumentation zur Gerätekonfiguration von Robolectric.
Von Gradle verwaltete Geräte
Mit dem Android-Gradle-Plug-in für von Gradle verwaltete Geräte (Gradle-managed devices, GMD) können Sie die Spezifikationen der Emulatoren und echten Geräte definieren, auf denen Ihre instrumentierten Tests ausgeführt werden. Erstellen Sie Spezifikationen für Geräte mit unterschiedlichen Bildschirmgrößen, um eine Teststrategie zu implementieren, bei der bestimmte Tests auf bestimmten Bildschirmgrößen ausgeführt werden müssen. Wenn Sie GMD mit Continuous Integration (CI) verwenden, können Sie dafür sorgen, dass die entsprechenden Tests bei Bedarf ausgeführt werden. Außerdem können Sie Emulatoren bereitstellen und starten und die CI-Einrichtung vereinfachen.
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"
}
}
}
}
}
Mehrere Beispiele für GMD finden Sie im Projekt testing-samples.
Firebase Test Lab
Mit Firebase Test Lab (FTL) oder einem ähnlichen Dienst für Gerätefarmen können Sie Ihre Tests auf bestimmten echten Geräten ausführen, auf die Sie möglicherweise keinen Zugriff haben, z. B. faltbare Geräte oder Tablets unterschiedlicher Größen. Firebase Test Lab ist ein kostenpflichtiger Dienst mit einem kostenlosen Kontingent. FTL unterstützt auch das Ausführen von Tests auf Emulatoren. Diese Dienste verbessern die Zuverlässigkeit und Geschwindigkeit instrumentierter Tests, da sie Geräte und Emulatoren im Voraus bereitstellen können.
Informationen zur Verwendung von FTL mit GMD finden Sie unter Tests mit von Gradle verwalteten Geräten skalieren.
Tests mit dem Test Runner filtern
Bei einer optimalen Teststrategie sollte nicht zweimal dasselbe geprüft werden. Daher müssen die meisten UI-Tests nicht auf mehreren Geräten ausgeführt werden. In der Regel filtern Sie Ihre UI-Tests, indem Sie alle oder die meisten davon auf einem Smartphone-Formfaktor und nur eine Teilmenge auf Geräten mit unterschiedlichen Bildschirmgrößen ausführen.
Sie können bestimmte Tests so annotieren, dass sie nur mit bestimmten Geräten ausgeführt werden, und dann mit dem Befehl, mit dem die Tests ausgeführt werden, ein Argument an den AndroidJUnitRunner übergeben.
Sie können beispielsweise verschiedene Annotationen erstellen:
annotation class TestExpandedWidth
annotation class TestCompactWidth
Und sie für verschiedene Tests verwenden:
class MyTestClass {
@Test
@TestExpandedWidth
fun myExample_worksOnTablet() {
...
}
@Test
@TestCompactWidth
fun myExample_worksOnPortraitPhone() {
...
}
}
Sie können dann die Eigenschaft android.testInstrumentationRunnerArguments.annotation verwenden, wenn Sie die Tests ausführen, um bestimmte Tests zu filtern. Wenn Sie beispielsweise von Gradle verwaltete Geräte verwenden:
$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Wenn Sie GMD nicht verwenden und Emulatoren in CI verwalten, prüfen Sie zuerst, ob der richtige Emulator oder das richtige Gerät bereit und verbunden ist, und übergeben Sie dann den Parameter an einen der Gradle-Befehle, um instrumentierte Tests auszuführen:
$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Beachten Sie, dass Espresso Device (siehe nächster Abschnitt) Tests auch anhand von Geräteeigenschaften filtern kann.
Espresso Device
Mit Espresso Device können Sie Aktionen auf Emulatoren in Tests ausführen, indem Sie instrumentierte Tests verwenden, z. B. Espresso-, Compose- oder UI Automator-Tests. Diese Aktionen können das Festlegen der Bildschirmgröße oder das Umschalten von faltbaren Zuständen oder Positionen umfassen. Sie können beispielsweise einen faltbaren Emulator steuern und in den Tischmodus versetzen. Espresso Device enthält auch JUnit-Regeln und -Annotationen, um bestimmte Funktionen zu erfordern:
@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 die folgenden Anforderungen hat:
- 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 Tests mit Annotationen filtern können. Wenn die annotierten Anforderungen nicht erfüllt sind, werden die Tests übersprungen.
RequiresDeviceMode-Annotation
Die RequiresDeviceMode Annotation kann mehrmals verwendet werden, um
einen Test anzugeben, der nur ausgeführt wird, wenn alle die DeviceMode Werte auf dem Gerät unterstützt werden.
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()))
}
}
RequiresDisplay-Annotation
Die RequiresDisplay Annotation ermöglicht es Ihnen, die Breite und Höhe des
Gerätebildschirms mithilfe von Größenklassen anzugeben, die Dimensions-Buckets
gemäß den offiziellen Fenstergrößenklassen definieren.
class OnDeviceTest {
...
@Test
@RequiresDisplay(EXPANDED, COMPACT)
fun myScreen_expandedWidthCompactHeight() {
...
}
}
Größe von Displays ändern
Verwenden Sie die Methode setDisplaySize(), um die Abmessungen des Bildschirms zur Laufzeit zu ändern. Verwenden Sie die Methode in Verbindung mit der DisplaySizeRule
Klasse, die dafür sorgt, dass alle Änderungen, die während der Tests vorgenommen wurden, vor dem
nächsten Test rückgängig gemacht werden.
@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 eines Displays mit setDisplaySize() ändern, wirkt sich das nicht auf die Dichte
des Geräts aus. Wenn eine Dimension nicht auf das Zielgerät passt, schlägt der Test
mit einer UnsupportedDeviceOperationException fehl. Verwenden Sie die Annotation RequiresDisplay, um zu verhindern, dass Tests in diesem Fall ausgeführt werden:
@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 StateRestorationTester Klasse wird verwendet, um die Wiederherstellung des Status
für zusammensetzbare Komponenten zu testen, ohne Aktivitäten neu zu erstellen. Dadurch werden Tests schneller und zuverlässiger, da die Neuerstellung von Aktivitäten ein komplexer Prozess mit mehreren Synchronisierungsmechanismen ist:
@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
val stateRestorationTester = StateRestorationTester(composeTestRule)
// Set content through the StateRestorationTester object.
stateRestorationTester.setContent {
MyApp()
}
// Simulate a config change.
stateRestorationTester.emulateSavedInstanceStateRestore()
}
Window Testing-Bibliothek
Die Window Testing-Bibliothek enthält Hilfsprogramme, mit denen Sie Tests schreiben können, die auf Funktionen im Zusammenhang mit der Fensterverwaltung angewiesen sind oder diese prüfen, z. B. Aktivitätseinbettung oder faltbare Funktionen. Das Artefakt ist über das Maven-Repository von Google verfügbar.
Sie können beispielsweise die FoldingFeature() Funktion verwenden, um ein
benutzerdefiniertes FoldingFeature zu generieren, das Sie in Compose-Vorschauen verwenden können. Verwenden Sie in Java,
die createFoldingFeature() Funktion.
In einer Compose-Vorschau 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 mit der
TestWindowLayoutInfo() Funktion Displayfunktionen in UI-Tests emulieren.
Im folgenden Beispiel wird ein FoldingFeature mit einem
HALF_OPENED
vertikalen Scharnier in der Mitte des Bildschirms simuliert. Anschließend wird geprüft, ob das
Layout das erwartete 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.
Zusätzliche Ressourcen
Dokumentation
- Qualitätsrichtlinien für Apps für große Bildschirme
- Apps auf Android-Geräten testen
- Compose-Layout testen
Beispiele
- WindowManager-Beispiel
- Espresso Device-Beispiele
- Now In Android
- Verwendet Screenshot-Tests, um verschiedene Bildschirmgrößen zu prüfen
Codelabs