Android udostępnia różne narzędzia i interfejsy API, które pomagają tworzyć testy dla różnych rozmiarów ekranu i okien.
DeviceConfigurationOverride
Komponent DeviceConfigurationOverride
umożliwia zastępowanie atrybutów konfiguracji w celu testowania wielu rozmiarów ekranu i okna w układach Compose. Zastąpienie ForcedSize
pasuje do każdego układu w dostępnej przestrzeni, dzięki czemu możesz przeprowadzać dowolne testy interfejsu na ekranach o dowolnym rozmiarze. Możesz na przykład używać małego telefonu do przeprowadzania wszystkich testów interfejsu, w tym testów interfejsu na dużych telefonach, urządzeniach składanych i tabletach.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}

Za pomocą tego komponentu możesz też ustawić skalę czcionki, motywy i inne właściwości, które chcesz przetestować w różnych rozmiarach okna.
Robolectric
Używaj Robolectric do przeprowadzania testów interfejsu opartych na Compose lub widokach na maszynie JVM lokalnie – nie są wymagane żadne urządzenia ani emulatory. Możesz skonfigurować Robolectric tak, aby używał określonych rozmiarów ekranu, a także innych przydatnych właściwości.
W tym przykładzie z Now in Android Robolectric jest skonfigurowany tak, aby emulować rozmiar ekranu 1000 x 1000 dp przy rozdzielczości 480 dpi:
@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 { ... }
Kwalifikatory możesz też ustawić w treści testu, jak w tym fragmencie z przykładu Now in Android:
val (width, height, dpi) = ...
// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")
Pamiętaj, że RuntimeEnvironment.setQualifiers()
aktualizuje zasoby systemu i aplikacji za pomocą nowej konfiguracji, ale nie wywołuje żadnych działań w przypadku aktywnych działań ani innych komponentów.
Więcej informacji znajdziesz w dokumentacji Robolectric Device Configuration (Konfiguracja urządzenia).
Urządzenia zarządzane przez Gradle
Wtyczka Androida do Gradle urządzenia zarządzane przez Gradle (GMD) umożliwia określanie specyfikacji emulatorów i prawdziwych urządzeń, na których są uruchamiane instrumentowane testy. Utwórz specyfikacje urządzeń o różnych rozmiarach ekranu, aby wdrożyć strategię testowania, w której określone testy muszą być przeprowadzane na określonych rozmiarach ekranu. Korzystając z GMD w trybie ciągłej integracji (CI), możesz mieć pewność, że w razie potrzeby zostaną uruchomione odpowiednie testy, a także udostępniać i uruchamiać emulatory oraz upraszczać konfigurację CI.
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"
}
}
}
}
}
Wiele przykładów GMD znajdziesz w projekcie testing-samples.
Laboratorium Firebase
Używaj Laboratorium Firebase (FTL) lub podobnej usługi farmy urządzeń, aby przeprowadzać testy na konkretnych urządzeniach, do których możesz nie mieć dostępu, np. na składanych telefonach lub tabletach o różnych rozmiarach. Laboratorium Firebase to płatna usługa z poziomem bezpłatnym. FTL umożliwia też przeprowadzanie testów na emulatorach. Te usługi zwiększają niezawodność i szybkość testów z instrumentacją, ponieważ mogą z wyprzedzeniem udostępniać urządzenia i emulatory.
Więcej informacji o używaniu FTL z GMD znajdziesz w artykule Skalowanie testów za pomocą urządzeń zarządzanych przez Gradle.
Testowanie filtrowania za pomocą narzędzia do uruchamiania testów
Optymalna strategia testowania nie powinna weryfikować tego samego dwa razy, więc większość testów interfejsu nie musi być przeprowadzana na wielu urządzeniach. Zazwyczaj filtrujesz testy interfejsu, uruchamiając wszystkie lub większość z nich na telefonie i tylko podzbiór na urządzeniach o różnych rozmiarach ekranu.
Możesz dodać adnotacje do niektórych testów, aby były uruchamiane tylko na określonych urządzeniach, a następnie przekazać argument do AndroidJUnitRunner za pomocą polecenia, które uruchamia testy.
Możesz na przykład utworzyć różne adnotacje:
annotation class TestExpandedWidth
annotation class TestCompactWidth
Używaj ich w różnych testach:
class MyTestClass {
@Test
@TestExpandedWidth
fun myExample_worksOnTablet() {
...
}
@Test
@TestCompactWidth
fun myExample_worksOnPortraitPhone() {
...
}
}
Podczas przeprowadzania testów możesz użyć właściwości android.testInstrumentationRunnerArguments.annotation
, aby filtrować konkretne testy. Jeśli na przykład używasz urządzeń zarządzanych przez Gradle:
$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Jeśli nie używasz GMD i zarządzasz emulatorami w CI, najpierw upewnij się, że odpowiedni emulator lub urządzenie jest gotowe i podłączone, a następnie przekaż parametr do jednego z poleceń Gradle, aby uruchomić testy instrumentowane:
$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Pamiętaj, że Espresso Device (patrz następna sekcja) może też filtrować testy za pomocą właściwości urządzenia.
Urządzenie do espresso
Używaj Espresso Device do wykonywania działań na emulatorach w testach z użyciem dowolnego rodzaju testów instrumentowanych, w tym testów Espresso, Compose lub UI Automator. Mogą one obejmować ustawianie rozmiaru ekranu lub przełączanie stanów składania i położenia. Możesz na przykład sterować emulatorem urządzenia składanego i ustawić go w trybie stołowym. Espresso Device zawiera też reguły i adnotacje JUnit, które wymagają określonych funkcji:
@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()))
}
}
Pamiętaj, że Espresso Device jest nadal w fazie alfa i ma następujące wymagania:
- Wtyczka Androida do obsługi Gradle w wersji 8.3 lub nowszej
- Emulator Androida w wersji 33.1.10 lub nowszej
- wirtualne urządzenie z Androidem z interfejsem API na poziomie 24 lub wyższym,
Filtrowanie testów
Espresso Device może odczytywać właściwości połączonych urządzeń, aby umożliwić Ci filtrowanie testów za pomocą adnotacji. Jeśli wymagania oznaczone adnotacjami nie zostaną spełnione, testy zostaną pominięte.
Adnotacja RequiresDeviceMode
Adnotacji RequiresDeviceMode
można użyć kilka razy, aby wskazać test, który będzie przeprowadzany tylko wtedy, gdy wszystkie wartości DeviceMode
są obsługiwane na urządzeniu.
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()))
}
}
Adnotacja RequiresDisplay
Adnotacja RequiresDisplay
umożliwia określenie szerokości i wysokości ekranu urządzenia za pomocą klas rozmiaru, które definiują przedziały wymiarów zgodnie z oficjalnymi klasami rozmiaru okna.
class OnDeviceTest {
...
@Test
@RequiresDisplay(EXPANDED, COMPACT)
fun myScreen_expandedWidthCompactHeight() {
...
}
}
Zmiana rozmiaru wyświetlaczy
Aby zmienić rozmiar ekranu w czasie działania, użyj metody setDisplaySize()
. Używaj tej metody w połączeniu z klasą DisplaySizeRule
, która zapewnia, że wszelkie zmiany wprowadzone podczas testów zostaną cofnięte przed kolejnym testem.
@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.
}
}
Zmiana rozmiaru ekranu za pomocą ikony setDisplaySize()
nie wpływa na gęstość urządzenia, więc jeśli wymiar nie mieści się na urządzeniu docelowym, test kończy się niepowodzeniem i wyświetla się ikona UnsupportedDeviceOperationException
. Aby w takim przypadku zapobiec uruchamianiu testów, użyj adnotacji RequiresDisplay
, aby je odfiltrować:
@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
Klasa StateRestorationTester
służy do testowania przywracania stanu komponentów kompozycyjnych bez ponownego tworzenia aktywności. Dzięki temu testy są szybsze i bardziej niezawodne, ponieważ odtwarzanie aktywności to złożony proces z wieloma mechanizmami synchronizacji:
@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
val stateRestorationTester = StateRestorationTester(composeTestRule)
// Set content through the StateRestorationTester object.
stateRestorationTester.setContent {
MyApp()
}
// Simulate a config change.
stateRestorationTester.emulateSavedInstanceStateRestore()
}
Biblioteka testów okien
Biblioteka Window Testing zawiera narzędzia, które pomagają pisać testy korzystające z funkcji związanych z zarządzaniem oknami lub weryfikujące te funkcje, takie jak osadzanie aktywności czy funkcje urządzeń składanych. Artefakt jest dostępny w repozytorium Maven Google.
Możesz na przykład użyć funkcji FoldingFeature()
, aby wygenerować niestandardowy FoldingFeature
, którego możesz używać w podglądach kompozycji. W języku Java użyj funkcji createFoldingFeature()
.
W podglądzie Compose możesz zaimplementować FoldingFeature
w ten sposób:
@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
MyApplicationTheme {
ExampleScreen(
displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
)
}
W testach interfejsu możesz też emulować funkcje wyświetlania za pomocą funkcji TestWindowLayoutInfo()
.
Poniższy przykład symuluje FoldingFeature
z HALF_OPENED
pionowym zawiasem na środku ekranu, a następnie sprawdza, czy układ jest zgodny z oczekiwanym:
Compose
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()
}
}
Wyświetlenia
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()))
}
}
Więcej przykładów znajdziesz w projekcie WindowManager.
Dodatkowe materiały
Dokumentacja
- Wskazówki dotyczące jakości aplikacji na duże ekrany
- Testowanie aplikacji na Androida
- Testowanie układu Compose
Próbki
- Przykład WindowManager
- Próbki urządzeń do espresso
- Now In Android
- Testowanie zrzutów ekranu w celu weryfikacji różnych rozmiarów ekranu
Codelabs