Motivi comuni

Puoi testare la tua app Compose con approcci e pattern consolidati.

Esegui i test in isolamento

ComposeTestRule ti consente di avviare un'attività che mostra qualsiasi elemento componibile: l'intera applicazione, una singola schermata o un piccolo elemento. È anche una buona pratica verificare che i composabili siano incapsulati correttamente e funzionino in modo indipendente, per consentire test della UI più semplici e mirati.

Ciò non significa che devi creare solo test dell'interfaccia utente dell'unità. Anche i test della UI che coprono parti più ampie della UI sono molto importanti.

Accedi all'attività e alle risorse dopo aver impostato i tuoi contenuti

Spesso è necessario impostare i contenuti in fase di test utilizzando composeTestRule.setContent e accedere alle risorse dell'attività, ad esempio per verificare che un testo visualizzato corrisponda a una risorsa stringa. Tuttavia, non puoi chiamare setContent su una regola creata con createAndroidComposeRule() se l'attività la chiama già.

Un pattern comune per raggiungere questo obiettivo è creare un AndroidComposeTestRule utilizzando un'attività vuota come ComponentActivity.

class MyComposeTest {

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

    @Test
    fun myTest() {
        // Start the app
        composeTestRule.setContent {
            MyAppTheme {
                MainScreen(uiState = exampleUiState, /*...*/)
            }
        }
        val continueLabel = composeTestRule.activity.getString(R.string.next)
        composeTestRule.onNodeWithText(continueLabel).performClick()
    }
}

Tieni presente che ComponentActivity deve essere aggiunto al file AndroidManifest.xml dell'app. Per farlo, aggiungi questa dipendenza al tuo modulo:

debugImplementation("androidx.compose.ui:ui-test-manifest:$compose_version")

Proprietà di semantica personalizzata

Puoi creare proprietà di semantica personalizzate per esporre le informazioni ai test. Per farlo, definisci un nuovo SemanticsPropertyKey e rendilo disponibile utilizzando SemanticsPropertyReceiver.

// Creates a semantics property of type Long.
val PickedDateKey = SemanticsPropertyKey<Long>("PickedDate")
var SemanticsPropertyReceiver.pickedDate by PickedDateKey

Ora utilizza questa proprietà nel modificatore semantics:

val datePickerValue by remember { mutableStateOf(0L) }
MyCustomDatePicker(
    modifier = Modifier.semantics { pickedDate = datePickerValue }
)

Dai test, utilizza SemanticsMatcher.expectValue per confermare il valore della proprietà:

composeTestRule
    .onNode(SemanticsMatcher.expectValue(PickedDateKey, 1445378400)) // 2015-10-21
    .assertExists()

Verifica il ripristino dello stato

Verifica che lo stato degli elementi di Compose venga ripristinato correttamente quando l'attività o il processo vengono ricreati. Esegui questi controlli senza fare affidamento sulla ricreazione dell'attività con la classe StateRestorationTester.

Questa classe ti consente di simulare la ricreazione di un componibile. È particolarmente utile per verificare l'implementazione di rememberSaveable.


class MyStateRestorationTests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun onRecreation_stateIsRestored() {
        val restorationTester = StateRestorationTester(composeTestRule)

        restorationTester.setContent { MainScreen() }

        // TODO: Run actions that modify the state

        // Trigger a recreation
        restorationTester.emulateSavedInstanceStateRestore()

        // TODO: Verify that state has been correctly restored.
    }
}

Testa diverse configurazioni dei dispositivi

Le app per Android devono adattarsi a molte condizioni mutevoli: dimensioni delle finestre, impostazioni internazionali, dimensioni dei caratteri, temi scuri e chiari e altro ancora. La maggior parte di queste condizioni deriva da valori a livello di dispositivo controllati dall'utente ed esposti con l'istanza Configuration corrente. Testare diverse configurazioni direttamente in un test è difficile, poiché il test deve configurare le proprietà a livello di dispositivo.

DeviceConfigurationOverride è un'API solo di test che ti consente di simulare diverse configurazioni dei dispositivi in modo localizzato per i contenuti @Composable in fase di test.

L'oggetto companion di DeviceConfigurationOverride ha le seguenti funzioni di estensione, che sostituiscono le proprietà di configurazione a livello di dispositivo:

Per applicare un override specifico, inserisci i contenuti in fase di test in una chiamata alla funzione di primo livello DeviceConfigurationOverride(), passando l'override da applicare come parametro.

Ad esempio, il seguente codice applica l'override DeviceConfigurationOverride.ForcedSize() per modificare la densità localmente, forzando il rendering del composable MyScreen in una finestra di grandi dimensioni in modalità Orizzontale, anche se il dispositivo su cui viene eseguito il test non supporta direttamente questa dimensione della finestra:

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.ForcedSize(DpSize(1280.dp, 800.dp))
    ) {
        MyScreen() // Will be rendered in the space for 1280dp by 800dp without clipping.
    }
}

Per applicare più override contemporaneamente, utilizza DeviceConfigurationOverride.then():

composeTestRule.setContent {
    DeviceConfigurationOverride(
        DeviceConfigurationOverride.FontScale(1.5f) then
            DeviceConfigurationOverride.FontWeightAdjustment(200)
    ) {
        Text(text = "text with increased scale and weight")
    }
}

Gestione personalizzata degli errori nei test

Il debug dei test della UI spesso richiede l'ispezione dello stato dello schermo e della gerarchia di composizione quando un'asserzione non va a buon fine.

Compose fornisce una pipeline nativa di gestione degli errori per semplificare la diagnostica. Puoi acquisire automaticamente screenshot e gerarchie della UI in caso di errore o registrare gestori personalizzati per inoltrare la telemetria degli arresti anomali a strumenti esterni.

Configura la gestione degli errori

Per configurare la gestione degli errori, passa un oggetto TestFailurePolicy a ComposeUiTestConfig.

Acquisisci gli artefatti degli errori integrati

Per acquisire screenshot e gerarchie della UI in caso di test non riuscito, imposta le proprietà screenshotCaptureMode e uiHierarchyCaptureMode in TestFailurePolicy.

class MyComposeTest {
    private val customConfig = ComposeUiTestConfig(
        failurePolicy = TestFailurePolicy(
            screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled,
            uiHierarchyCaptureMode = TestFailurePolicy.CaptureMode.Enabled
        )
    )

    @Test
    fun myFirstTest() = runComposeUiTest(config = customConfig) {
        // ...
    }
}

Utilizza un gestore degli errori personalizzato

Per definire un comportamento personalizzato per gli errori dei test, aggiungi un TestFailureHandler all'elenco failureHandlers. Ogni gestore riceve un oggetto FailureContext che contiene l'errore originale e un elenco di artefatti generati dai gestori della pipeline precedenti.

class MyComposeTestWithHandler {
    private val customConfig = ComposeUiTestConfig(
        failurePolicy = TestFailurePolicy(
            screenshotCaptureMode = TestFailurePolicy.CaptureMode.Enabled,
            failureHandlers = listOf(
                TestFailureHandler { context ->
                    val screenshot = context.artifacts.firstOrNull {
                        it.type == FailureArtifact.Type.Screenshot
                    }
                    // ...
                }
            )
        )
    )

    @get:Rule
    val rule = createComposeRule(config = customConfig)

    // ...
}

Configura le acquisizioni per un'intera suite di test

Puoi attivare l'acquisizione degli artefatti degli errori per un'intera suite di test passando gli argomenti del runner di strumentazione nel file build.gradle del modulo. In questo modo non è necessario aggiornare i singoli file di test.

// build.gradle.kts
android {
    defaultConfig {
        // ...
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isUiHierarchyCaptureEnabled"] = "true"
        testInstrumentationRunnerArguments["androidx.compose.ui.test.failure.isScreenshotCaptureEnabled"] = "true"
    }
}

Precedenza della configurazione

Il framework valuta sia gli argomenti del runner TestFailurePolicy locale sia quelli a livello di suite:

  • Se imposti esplicitamente una modalità su CaptureMode.Enabled/Disabled nel tuo test failurePolicy, l'argomento del runner viene sostituito.
  • Se imposti una modalità su CaptureMode.Unspecified (o lasci failurePolicy come null), il framework utilizza l'argomento del runner.

Risorse aggiuntive

  • Testa le app su Android: la pagina di destinazione principale dei test su Android offre una visione più ampia dei concetti fondamentali e delle tecniche di test.
  • Concetti fondamentali sul test di app Android: scopri di più sui concetti di base alla base del test di un'app per Android.
  • Test locali: puoi eseguire alcuni test localmente, sulla tua workstation.
  • Test di instrumentazione: è buona norma eseguire anche i test di instrumentazione. ovvero test eseguiti direttamente sul dispositivo.
  • Integrazione continua: l'integrazione continua ti consente di integrare i test nella pipeline di deployment.
  • Testa diverse dimensioni dello schermo:con così tanti dispositivi a disposizione degli utenti, devi eseguire test per diverse dimensioni dello schermo.
  • Espresso: sebbene sia destinato alle UI basate su View, la conoscenza di Espresso può comunque essere utile per alcuni aspetti dei test di Compose.