Android fornisce una serie di strumenti e API che possono aiutarti a creare test per schermi e finestre di dimensioni diverse.
Override configurazione dispositivo
Il composable DeviceConfigurationOverride
ti consente di eseguire l'override degli attributi di configurazione per testare più dimensioni di schermo e finestra nei layout di Compose. L'override ForcedSize
si adatta a qualsiasi layout nello spazio disponibile,
in modo da poter eseguire qualsiasi
test dell'interfaccia utente su qualsiasi dimensione dello schermo. Ad esempio, puoi utilizzare un fattore di forma di uno smartphone di piccole dimensioni per eseguire tutti i test dell'interfaccia utente, inclusi quelli per smartphone di grandi dimensioni, dispositivi pieghevoli e tablet.
DeviceConfigurationOverride(
DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
) {
MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
}
Inoltre, puoi utilizzare questo componibile per impostare la scala del carattere, i temi e altre proprietà che potresti voler testare su dimensioni di finestre diverse.
Robolectric
Utilizza Robolectric per eseguire test dell'interfaccia utente basati su Compose o sulle visualizzazioni sulla JVM localmente, senza bisogno di dispositivi o emulatori. Puoi configurare Robolectric in modo che utilizzi dimensioni dello schermo specifiche, tra le altre proprietà utili.
Nel seguente esempio di Novità di Android, Robolectric è configurato per emulare una dimensione dello schermo di 1000 x 1000 dp con una risoluzione di 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 { ... }
Puoi anche impostare i qualificatori dal corpo del test come indicato in questo snippet dell'esempio Ora su Android:
val (width, height, dpi) = ...
// Set qualifiers from specs.
RuntimeEnvironment.setQualifiers("w${width}dp-h${height}dp-${dpi}dpi")
Tieni presente che RuntimeEnvironment.setQualifiers()
aggiorna le risorse del sistema e dell'applicazione con la nuova configurazione, ma non attiva alcuna azione sulle attività attive o su altri componenti.
Per saperne di più, consulta la documentazione relativa alla configurazione del dispositivo di Robolectric.
Dispositivi gestiti da Gradle
Il plug-in Gradle per Android dispositivi gestiti da Gradle (GMD) consente di definire le specifiche degli emulatori e dei dispositivi reali su cui vengono eseguiti i test strumentati. Crea le specifiche per i dispositivi con schermi di dimensioni diverse al fine di implementare una strategia di test in cui determinati test devono essere eseguiti su schermi di determinate dimensioni. Utilizzando GMD con l'integrazione continua (CI), puoi assicurarti che i test appropriati vengano eseguiti quando necessario, eseguire il provisioning e avviare gli emulatori e semplificare la configurazione dell'integrazione continua.
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"
}
}
}
}
}
Puoi trovare diversi esempi di GMD nel progetto testing-samples.
Firebase Test Lab
Utilizza Firebase Test Lab (FTL) o un servizio di farm di dispositivi simile per eseguire i test su dispositivi reali specifici a cui potresti non avere accesso, ad esempio dispositivi pieghevoli o tablet di varie dimensioni. Firebase Test Lab è un servizio a pagamento con un livello senza costi. FTL supporta anche l'esecuzione di test su emulatori. Questi servizi migliorano l'affidabilità e la velocità dei test con strumenti perché possono eseguire il provisioning di dispositivi ed emulatori in anticipo.
Per informazioni sull'utilizzo di FTL con GMD, consulta Eseguire il scaling dei test con i dispositivi gestiti da Gradle.
Testare il filtro con il programma di test
Una strategia di test ottimale non deve verificare la stessa cosa due volte, quindi la maggior parte dei test dell'interfaccia utente non deve essere eseguita su più dispositivi. In genere, i test dell'interfaccia utente vengono filtrati eseguendoli tutti o la maggior parte su un fattore di forma di uno smartphone e solo un sottoinsieme su dispositivi con schermi di dimensioni diverse.
Puoi annotare determinati test in modo che vengano eseguiti solo con determinati dispositivi e poi passare un argomento ad AndroidJUnitRunner utilizzando il comando che esegue i test.
Ad esempio, puoi creare diverse annotazioni:
annotation class TestExpandedWidth
annotation class TestCompactWidth
Usali in diversi test:
class MyTestClass {
@Test
@TestExpandedWidth
fun myExample_worksOnTablet() {
...
}
@Test
@TestCompactWidth
fun myExample_worksOnPortraitPhone() {
...
}
}
Potrai quindi utilizzare la proprietà android.testInstrumentationRunnerArguments.annotation
durante i test per filtrare quelli specifici. Ad esempio, se utilizzi dispositivi gestiti da Gradle:
$ ./gradlew pixelTabletApi30DebugAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Se non utilizzi GMD e gestisci gli emulatori in CI, assicurati innanzitutto che l'emulatore o il dispositivo corretto sia pronto e connesso, quindi passa il parametro a uno dei comandi Gradle per eseguire i test con strumenti:
$ ./gradlew connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.annotation='com.sample.TestExpandedWidth'
Tieni presente che il dispositivo Espresso (vedi la prossima sezione) può anche filtrare i test utilizzando le proprietà del dispositivo.
Dispositivo per espresso
Utilizza Espresso Device per eseguire azioni sugli emulatori nei test utilizzando qualsiasi tipo di test strumentato, inclusi i test Espresso, Compose o UI Automator. Queste azioni possono includere l'impostazione delle dimensioni dello schermo o l'attivazione/disattivazione degli stati o delle posizioni del dispositivo pieghevole. Ad esempio, puoi controllare un emulatore pieghevole e impostarlo in modalità da tavolo. Il dispositivo Espresso contiene anche regole e annotazioni JUnit per richiedere determinate funzionalità:
@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()))
}
}
Tieni presente che Espresso Device è ancora in fase alfa e presenta i seguenti requisiti:
- Plug-in Android Gradle 8.3 o versioni successive
- Android Emulator 33.1.10 o versioni successive
- Dispositivo virtuale Android con livello API 24 o versioni successive
Filtrare i test
Espresso Device può leggere le proprietà dei dispositivi connessi per consentirti di filtrare i test utilizzando le annotazioni. Se i requisiti annotati non vengono soddisfatti, i test vengono ignorati.
Annotazione RequiresDeviceMode
L'annotazione RequiresDeviceMode
può essere utilizzata più volte per indicare un test che verrà eseguito solo se tutti i valori DeviceMode
sono supportati sul dispositivo.
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()))
}
}
Annotazione RequiresDisplay
L'annotazione RequiresDisplay
consente di specificare la larghezza e l'altezza dello schermo del dispositivo utilizzando le classi di dimensioni, che definiscono i bucket delle dimensioni in base alle classi di dimensioni della finestra ufficiali.
class OnDeviceTest {
...
@Test
@RequiresDisplay(EXPANDED, COMPACT)
fun myScreen_expandedWidthCompactHeight() {
...
}
}
Ridimensionare le visualizzazioni
Utilizza il metodo setDisplaySize()
per ridimensionare le dimensioni dello schermo
in fase di esecuzione. Utilizza il metodo in combinazione con la classe DisplaySizeRule
, per assicurarti che tutte le modifiche apportate durante i test vengano annullate prima del test successivo.
@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.
}
}
Il ridimensionamento di un display con setDisplaySize()
non influisce sulla densità
del dispositivo; pertanto, se una dimensione non rientra nel dispositivo target, il test
non va a buon fine con UnsupportedDeviceOperationException
. Per evitare che i test vengano eseguiti in questo caso, utilizza l'annotazione RequiresDisplay
per escluderli:
@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.
}
}
Tester del ripristino dello stato
La classe StateRestorationTester
viene utilizzata per testare il ripristino dello stato per i componenti composable senza ricreare le attività. In questo modo, i test sono più rapidi e affidabili, poiché la ricreazione delle attività è un processo complesso con più meccanismi di sincronizzazione:
@Test
fun compactDevice_selectedEmailEmailRetained_afterConfigChange() {
val stateRestorationTester = StateRestorationTester(composeTestRule)
// Set content through the StateRestorationTester object.
stateRestorationTester.setContent {
MyApp()
}
// Simulate a config change.
stateRestorationTester.emulateSavedInstanceStateRestore()
}
Libreria per i test delle finestre
La libreria Window Testing contiene utilità che ti aiutano a scrivere test che si basano su o verificano le funzionalità relative alla gestione delle finestre, come l'incorporamento delle attività o le caratteristiche pieghevoli. L'elemento è disponibile tramite il Maven Repository di Google.
Ad esempio, puoi utilizzare la funzione FoldingFeature()
per generare un FoldingFeature
personalizzato, che puoi utilizzare nelle anteprime di Compose. In Java,
utilizza la funzione createFoldingFeature()
.
In un'anteprima di Compose, potresti implementare FoldingFeature
nel seguente modo:
@Preview(showBackground = true, widthDp = 480, heightDp = 480)
@Composable private fun FoldablePreview() =
MyApplicationTheme {
ExampleScreen(
displayFeatures = listOf(FoldingFeature(Rect(0, 240, 480, 240)))
)
}
Inoltre, puoi emulare le funzionalità di visualizzazione nei test dell'interfaccia utente utilizzando la funzione
TestWindowLayoutInfo()
.
L'esempio seguente simula un FoldingFeature
con un HALF_OPENED
giunto verticale al centro dello schermo, quindi controlla se il layout è quello previsto:
Scrivi
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()
}
}
Visualizzazioni
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()))
}
}
Puoi trovare altri esempi nel progetto WindowManager.
Risorse aggiuntive
Documentazione
- Norme sulla qualità delle app per schermi di grandi dimensioni
- Testare le app su Android
- Testare il layout di Componi
Campioni
- Esempio di WindowManager
- Esempi di dispositivi per espresso
- Novità di Android
- Utilizza i test degli screenshot per verificare diverse dimensioni dello schermo
Codelab