Sincroniza tus pruebas

Las pruebas de Compose se sincronizan de forma predeterminada con tu IU. Cuando llames a una aserción o una acción con ComposeTestRule, la prueba se sincronizará antes y se esperará hasta que el árbol de IU esté inactivo.

Normalmente, no es necesario que realices ninguna acción. Sin embargo, hay algunos casos extremos que debes conocer.

Cuando se sincroniza una prueba, tu app de Compose está avanzada a tiempo con un reloj virtual. Eso significa que las pruebas de Compose no se ejecutan en tiempo real, por lo que pueden pasar tan rápido como sea posible.

Sin embargo, si no usas los métodos que sincronizan tus pruebas, no se producirá una recomposición, y la IU se pausará.

@Test
fun counterTest() {
    val myCounter = mutableStateOf(0) // State that can cause recompositions.
    var lastSeenValue = 0 // Used to track recompositions.
    composeTestRule.setContent {
        Text(myCounter.value.toString())
        lastSeenValue = myCounter.value
    }
    myCounter.value = 1 // The state changes, but there is no recomposition.

    // Fails because nothing triggered a recomposition.
    assertTrue(lastSeenValue == 1)

    // Passes because the assertion triggers recomposition.
    composeTestRule.onNodeWithText("1").assertExists()
}

Ten en cuenta que este requisito solo se aplica a las jerarquías de Compose y no al resto de la app.

Cómo inhabilitar la sincronización automática

Cuando llamas a una aserción o una acción a través de ComposeTestRule, como assertExists(), tu prueba se sincroniza con la IU de Compose. En algunos casos, puedes detener esta sincronización y controlar tú mismo el reloj. Por ejemplo, puedes controlar el tiempo para tomar capturas de pantalla precisas de una animación en un punto en el que la IU esté ocupada. Para inhabilitar la sincronización automática, configura la propiedad autoAdvance de mainClock como false:

composeTestRule.mainClock.autoAdvance = false

Normalmente, avanzarás el tiempo tú mismo. Puedes avanzar de a un fotograma con advanceTimeByFrame() o por una duración específica con advanceTimeBy():

composeTestRule.mainClock.advanceTimeByFrame()
composeTestRule.mainClock.advanceTimeBy(milliseconds)

Recursos inactivos

Compose puede sincronizar pruebas y la IU para que todas las acciones y aserciones se realicen en estado inactivo, a la espera del reloj o avanzándolo según sea necesario. Sin embargo, algunas operaciones asíncronas cuyos resultados afectan el estado de la IU se pueden ejecutar en segundo plano mientras la prueba no las tiene en cuenta.

Crea y registra estos recursos inactivos en tu prueba para que se los tenga en cuenta cuando determines si la app en cuestión está ocupada o inactiva. No tienes que realizar ninguna acción, a menos que necesites registrar recursos inactivos adicionales, por ejemplo, si ejecutas un trabajo en segundo plano que no se sincroniza con Espresso ni Compose.

Esta API es muy similar a los recursos inactivos de Espresso para indicar si el sujeto en cuestión está inactivo o ocupado. Usa la regla de prueba de Compose para registrar la implementación del IdlingResource.

composeTestRule.registerIdlingResource(idlingResource)
composeTestRule.unregisterIdlingResource(idlingResource)

Sincronización manual

En algunos casos, debes sincronizar la IU de Compose con otras partes de la prueba o la app que estás probando.

La función waitForIdle() espera a que Compose esté inactivo, pero depende de la propiedad autoAdvance:

composeTestRule.mainClock.autoAdvance = true // Default
composeTestRule.waitForIdle() // Advances the clock until Compose is idle.

composeTestRule.mainClock.autoAdvance = false
composeTestRule.waitForIdle() // Only waits for idling resources to become idle.

Ten en cuenta que, en ambos casos, waitForIdle() también espera a que se hayan pasado el diseño y dibujo pendientes.

Además, puedes adelantar el reloj hasta que se cumpla una condición determinada con advanceTimeUntil().

composeTestRule.mainClock.advanceTimeUntil(timeoutMs) { condition }

Ten en cuenta que la condición determinada debe comprobar el estado que puede verse afectado por este reloj (solo funciona con el estado de Compose).

Esperar condiciones

Cualquier condición que dependa de un trabajo externo, como la carga de datos o la medición o el dibujo de Android (es decir, medición o dibujo externo a Compose), debe usar un concepto más general, como waitUntil():

composeTestRule.waitUntil(timeoutMs) { condition }

También puedes usar cualquiera de los ayudantes waitUntil:

composeTestRule.waitUntilAtLeastOneExists(matcher, timeoutMs)

composeTestRule.waitUntilDoesNotExist(matcher, timeoutMs)

composeTestRule.waitUntilExactlyOneExists(matcher, timeoutMs)

composeTestRule.waitUntilNodeCount(matcher, count, timeoutMs)

Recursos adicionales

  • Cómo probar apps en Android: La página de destino principal de pruebas de Android proporciona una vista más amplia de los aspectos básicos y las técnicas de prueba.
  • Aspectos básicos de las pruebas: Obtén más información sobre los conceptos básicos de las pruebas de una app para Android.
  • Pruebas locales: Puedes ejecutar algunas pruebas de forma local, en tu propia estación de trabajo.
  • Pruebas instrumentadas: Se recomienda ejecutar pruebas instrumentadas. Es decir, pruebas que se ejecutan directamente en el dispositivo.
  • Integración continua: La integración continua te permite integrar tus pruebas en la canalización de implementación.
  • Prueba diferentes tamaños de pantalla: Con muchos dispositivos disponibles para los usuarios, debes probar diferentes tamaños de pantalla.
  • Espresso: Si bien está diseñado para IUs basadas en objetos View, el conocimiento de Espresso puede ser útil para algunos aspectos de las pruebas de Compose.