Test delle API

Esistono tre modi principali per interagire con gli elementi dell'interfaccia utente:

  • I rilevatori ti consentono di selezionare uno o più elementi (o nodi nell'albero della semantica) per creare asserzioni o eseguire azioni su questi elementi.
  • Le asserzioni vengono utilizzate per verificare che gli elementi esistano o abbiano determinati attributi.
  • Le azioni iniettano eventi utente simulati negli elementi, ad esempio clic o altri gesti.

Alcune di queste API accettano un SemanticsMatcher per fare riferimento a uno o più nodi nell'albero della semantica.

Ricercatori

Puoi utilizzare onNode e onAllNodes per selezionare rispettivamente uno o più nodi, ma puoi anche utilizzare strumenti di ricerca di convenienza per le ricerche più comuni, ad esempio onNodeWithText e onNodeWithContentDescription. Puoi sfogliare l'elenco completo nella scheda di riferimento per il test di Compose.

Seleziona un singolo nodo

composeTestRule.onNode(<<SemanticsMatcher>>, useUnmergedTree = false): SemanticsNodeInteraction
// Example
composeTestRule
    .onNode(hasText("Button")) // Equivalent to onNodeWithText("Button")

Seleziona più nodi

composeTestRule
    .onAllNodes(<<SemanticsMatcher>>): SemanticsNodeInteractionCollection
// Example
composeTestRule
    .onAllNodes(hasText("Button")) // Equivalent to onAllNodesWithText("Button")

Albero non unito

Alcuni nodi uniscono le informazioni semantiche dei relativi figli. Ad esempio, un pulsante con due elementi di testo unisce le etichette degli elementi di testo:

MyButton {
    Text("Hello")
    Text("World")
}

Da un test, utilizza printToLog() per visualizzare l'albero della semantica:

composeTestRule.onRoot().printToLog("TAG")

Questo codice visualizza il seguente output:

Node #1 at (...)px
 |-Node #2 at (...)px
   Role = 'Button'
   Text = '[Hello, World]'
   Actions = [OnClick, GetTextLayoutResult]
   MergeDescendants = 'true'

Se devi trovare una corrispondenza con un nodo di quello che sarebbe l'albero non unito, puoi impostare useUnmergedTree su true:

composeTestRule.onRoot(useUnmergedTree = true).printToLog("TAG")

Questo codice stampa il seguente output:

Node #1 at (...)px
 |-Node #2 at (...)px
   OnClick = '...'
   MergeDescendants = 'true'
    |-Node #3 at (...)px
    | Text = '[Hello]'
    |-Node #5 at (83.0, 86.0, 191.0, 135.0)px
      Text = '[World]'

Il parametro useUnmergedTree è disponibile in tutti i finder. Ad esempio, qui viene utilizzato in un cercatore di onNodeWithText.

composeTestRule
    .onNodeWithText("World", useUnmergedTree = true).assertIsDisplayed()

Affermazioni

Controlla le asserzioni chiamando assert() sul SemanticsNodeInteraction restituito da un cercatore con uno o più corrispondenti:

// Single matcher:
composeTestRule
    .onNode(matcher)
    .assert(hasText("Button")) // hasText is a SemanticsMatcher

// Multiple matchers can use and / or
composeTestRule
    .onNode(matcher).assert(hasText("Button") or hasText("Button2"))

Puoi anche utilizzare funzioni di utilità per le asserzioni più comuni, ad esempio assertExists, assertIsDisplayed e assertTextEquals. Puoi sfogliare l'elenco completo nel cheat sheet di Compose Testing.

Esistono anche funzioni per controllare le asserzioni su una raccolta di nodi:

// Check number of matched nodes
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertCountEquals(4)
// At least one matches
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertAny(hasTestTag("Drummer"))
// All of them match
composeTestRule
    .onAllNodesWithContentDescription("Beatle").assertAll(hasClickAction())

Azioni

Per iniettare un'azione in un nodo, chiama una funzione perform…():

composeTestRule.onNode(...).performClick()

Ecco alcuni esempi di azioni:

performClick(),
performSemanticsAction(key),
performKeyPress(keyEvent),
performGesture { swipeLeft() }

Puoi sfogliare l'elenco completo nel cheat sheet di Compose Testing.

Confrontatori

Esistono diversi corrispondenti disponibili per testare il codice Compose.

Matcher gerarchici

I corrispondenti gerarchici ti consentono di spostarti verso l'alto o verso il basso nella struttura ad albero della semantica ed eseguire la corrispondenza.

fun hasParent(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnySibling(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyAncestor(matcher: SemanticsMatcher): SemanticsMatcher
fun hasAnyDescendant(matcher: SemanticsMatcher):  SemanticsMatcher

Ecco alcuni esempi di utilizzo di questi corrispondenti:

composeTestRule.onNode(hasParent(hasText("Button")))
    .assertIsDisplayed()

Selettori

Un modo alternativo per creare test è utilizzare i selettori, che possono rendere alcuni test più leggibili.

composeTestRule.onNode(hasTestTag("Players"))
    .onChildren()
    .filter(hasClickAction())
    .assertCountEquals(4)
    .onFirst()
    .assert(hasText("John"))

Puoi sfogliare l'elenco completo nel cheat sheet di Compose Testing.

Risorse aggiuntive

  • Testare le app su Android: la pagina di destinazione principale per i test su Android offre una visione più ampia delle nozioni di base e delle tecniche di test.
  • Nozioni di base sui test: scopri di più sui concetti fondamentali alla base del test di un'app per Android.
  • Test locali: puoi eseguire alcuni test localmente, sulla tua workstation.
  • Test con strumenti: è buona prassi eseguire anche test con strumenti. ovvero i test eseguiti direttamente sul dispositivo.
  • Integrazione continua: l'integrazione continua ti consente di integrare i test nella pipeline di deployment.
  • Prova schermi di dimensioni diverse: con alcuni dispositivi a disposizione degli utenti, ti conviene eseguire test per schermi di dimensioni diverse.
  • Espresso: sebbene sia destinato alle UI basate su visualizzazioni, le conoscenze di Espresso possono essere utili per alcuni aspetti dei test di Compose.