Cómo probar la app de Cupcake

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.

1. Introducción

En el codelab Cómo navegar entre pantallas con Compose, aprendiste a agregar la navegación a una app de Compose con el componente Navigation de Jetpack Compose.

La app de Cupcake tiene varias pantallas para navegar y una variedad de acciones que el usuario puede ejecutar. Esta app te brinda una gran oportunidad para perfeccionar tu habilidad de pruebas automatizadas. En este codelab, escribirás varias pruebas de IU para la app de Cupcake y aprenderás a abordar la maximización de la cobertura de las pruebas.

Requisitos previos

Qué aprenderás

  • Probarás el componente Navigation de Jetpack con Compose.
  • Crearás un estado coherente de la IU para cada prueba de IU.
  • Crearás funciones auxiliares para las pruebas.

Qué compilarás

  • Pruebas de la IU de la app de Cupcake

Requisitos

  • La versión más reciente de Android Studio
  • Conexión a Internet a fin de descargar el código de inicio

2. Descarga el código de inicio

  1. En Android Studio, abre la carpeta basic-android-kotlin-compose-training-cupcake.
  2. Abre el código de la app de Cupcake en Android Studio.

3. Cómo configurar Cupcake para las pruebas de IU

Cómo agregar la dependencia androidTest

La herramienta de compilación de Gradle te permite agregar dependencias para módulos específicos. Esta funcionalidad evita que se compilen dependencias de forma innecesaria. Ya conoces la configuración de implementation a la hora de incluir dependencias en un proyecto. Usaste esta palabra clave para importar dependencias en el archivo build.gradle del módulo de la app. El uso de la palabra clave implementation hace que esa dependencia esté disponible para todos los conjuntos de fuentes en ese módulo. En este punto del curso, ya tienes experiencia con los conjuntos de orígenes main, test y androidTest.

Las pruebas de IU se encuentran en sus propios conjuntos de orígenes llamados androidTest. Las dependencias que solo se necesitan para este módulo no necesitan compilarse en otros módulos, como main, que contiene el código de la app. Cuando agregues una dependencia que solo usen las pruebas de IU, usa la palabra clave androidTestImplementation a fin de declarar la dependencia en el archivo build.gradle del módulo de la app. Esto garantiza que las dependencias de las pruebas de IU se compilen solo cuando ejecutes pruebas de IU.

Completa los siguientes pasos a fin de agregar las dependencias necesarias para escribir pruebas de IU:

  1. Abre el archivo app/build.gradle.
  2. Agrega las siguientes dependencias a la sección de dependencias del archivo:
androidTestImplementation "androidx.compose.ui:ui-test-junit4:$compose_version"
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-intents:3.4.0'
androidTestImplementation "androidx.navigation:navigation-testing:2.5.0"
debugImplementation "androidx.compose.ui:ui-test-manifest:$compose_version"
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"

Cómo crear el directorio de prueba de la IU

  1. Haz clic con el botón derecho en el directorio src en la vista de proyecto y selecciona New > Directory.

288ebc5eae5fba2e.png

  1. Selecciona la opción androidTest/java.

12ec57f9d9e907de.png

Cómo crear el paquete de prueba

  1. Haz clic con el botón derecho en el directorio androidTest/java de la ventana del proyecto y selecciona New > Package.

5104da51d0529eb7.png

  1. Nombra el paquete com.example.cupcake.test. da0e0458fdcb1cfc.png

Cómo crear la clase de prueba de navegación

En el directorio test, crea una nueva clase de Kotlin llamada CupcakeScreenNavigationTest.

7336dbed4e215b68.png

4. Cómo configurar el host de navegación

En un codelab anterior, aprendiste que las pruebas de IU en Compose requieren una regla de prueba de Compose. Lo mismo ocurre cuando se prueba Jetpack Navigation. Sin embargo, la navegación de prueba requiere una configuración adicional mediante la regla de prueba de Compose.

Cuando pruebes la navegación de Compose, no tendrás acceso al mismo NavHostController que tienes en el código de la app. Sin embargo, puedes usar un TestNavHostController y configurar la regla de prueba con este controlador de navegación. En esta sección, aprenderás a configurar y reutilizar la regla de prueba para las pruebas de navegación.

  1. En CupcakeScreenNavigationTest.kt, crea una regla de prueba con createAndroidComposeRule y pasa ComponentActivity como el parámetro de tipo.
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()

A fin de asegurarte de que tu app se dirija al lugar correcto, debes hacer referencia a una instancia de TestNavHostController de modo que se verifique la ruta del host de navegación cuando la app realice acciones para navegar.

  1. Crea una instancia de TestNavHostController como una variable lateinit. En Kotlin, se usa la palabra clave lateinit a los efectos de declarar una propiedad que se puede inicializar después de declarar el objeto.
private lateinit var navController: TestNavHostController

Luego, especifica el elemento que admite composición que deseas usar para las pruebas de la IU.

  1. Crea un método llamado setupCupcakeNavHost().
  2. En el método setupCupcakeNavHost(), llama al método setContent() en la regla de prueba de Compose que creaste.
  3. Dentro de la lambda pasada al método setContent(), llama al elemento CupcakeApp() que admite composición.
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       CupcakeApp()
   }
}

Ahora debes crear el objeto TestNavHostContoller en la clase de prueba. Usarás este objeto más adelante para determinar el estado de navegación, ya que la app usa el controlador a fin de navegar por las diferentes pantallas de la app de Cupcake.

  1. Configura el host de navegación mediante la lambda que creaste antes. Inicializa la variable navController que creaste, registra un navegador y pasa ese TestNavHostController al elemento CupcakeApp que admite composición.
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       navController =
           TestNavHostController(LocalContext.current)
       navController.navigatorProvider.addNavigator(
           ComposeNavigator()
       )
       CupcakeApp(navController = navController)
   }
}

Cada prueba de la clase CupcakeScreenNavigationTest implica probar un aspecto de la navegación. Por lo tanto, cada prueba depende del objeto TestNavHostController que creaste. En lugar de tener que llamar manualmente a la función setupCupcakeNavHost() para cada prueba a fin de configurar el controlador de navegación, puedes hacer que eso suceda automáticamente con la anotación @Before que proporciona la biblioteca junit. Cuando un método se anota con @Before, se ejecuta antes de cada método anotado con @Test.

  1. Agrega la anotación @Test al método setupCupcakeNavHost().
@Before
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       navController =
           TestNavHostController(LocalContext.current)
       navController.navigatorProvider.addNavigator(
           ComposeNavigator()
       )
       CupcakeApp(navController = navController)
   }
}

5. Cómo escribir pruebas de navegación

Cómo verificar el destino de inicio

Recuerda que, cuando compilaste la app de Cupcake, creaste una clase enum llamada Cupcake que contenía constantes para determinar la navegación de la app.

CupcakeScreen.kt

/**
* enum values that represent the screens in the app
*/
enum class CupcakeScreen(@StringRes val title: Int) {
   Start(title = R.string.app_name),
   Flavor(title = R.string.choose_flavor),
   Pickup(title = R.string.choose_pickup_date),
   Summary(title = R.string.order_summary)
}

Todas las apps que tienen una IU tienen una pantalla principal de algún tipo. Para Cupcake, esa pantalla es la pantalla de inicio del pedido. El controlador de navegación del elemento CupcakeApp que admite composición usa el elemento Start del elemento CupcakeScreen de tipo enum a fin de determinar cuándo navegar a esta pantalla. Cuando se inicia la app, si no existe una ruta de destino, la correspondiente al host de navegación se establece en Cupcake.Start.name.

Primero, debes escribir una prueba para verificar que la pantalla de inicio del pedido sea la ruta de destino actual cuando se inicia la app.

  1. Crea una función llamada cupcakeNavHost_verifyStartDestination() y anótala con @Test.
@Test
fun cupcakeNavHost_verifyStartDestination() {
}

Ahora debes confirmar que la ruta de destino inicial del controlador de navegación sea la pantalla de inicio del pedido.

  1. Confirma que el nombre de ruta esperado (en este caso, Cupcake.Start.name) sea igual a la ruta de destino de la entrada actual de la pila de actividades del controlador de navegación.
import org.junit.Assert.assertEquals
...

@Test
fun cupcakeNavHost_verifyStartDestination() {assertEquals(Cupcake.Start.name, currentBackStackEntry?.destination?.route)
}

Cómo crear un método auxiliar

Las pruebas de IU a menudo requieren la repetición de pasos para colocar la IU en un estado en el que se pueda probar una parte específica de ella. Una IU personalizada también puede requerir aserciones complejas que necesiten varias líneas de código. La aserción que escribiste en la sección anterior requiere mucho código, y la utilizas muchas veces cuando pruebas la navegación en la app de Cupcake. En estas situaciones, escribir métodos auxiliares en tus pruebas evita que escribas código duplicado.

Para cada prueba de navegación que escribas, debes usar la propiedad name de los elementos CupcakeScreen de tipo enum a fin de verificar que la ruta de destino actual del controlador de navegación sea la correcta. Debes escribir una función auxiliar a la que puedas llamar cada vez que desees realizar esa aserción.

Para crear esta función auxiliar, completa los siguientes pasos:

  1. Crea un archivo Kotlin vacío en el directorio test llamado ScreenAssertions.

ac62e5b9b8153027.png

  1. Agrega una función de extensión a la clase NavController llamada assertCurrentRouteName() y pasa una string para el nombre de ruta esperado en la firma del método.
fun NavController.assertCurrentRouteName(expectedRouteName: String) {

}
  1. En esta función, confirma que expectedRouteName sea igual a la ruta de destino de la entrada actual de la pila de actividades del controlador de navegación.
import org.junit.Assert.assertEquals
...

fun NavController.assertCurrentRouteName(expectedRouteName: String) {
   assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route)
}
  1. Abre el archivo CupcakeScreenNavigationTest y modifica la función cupcakeNavHost_verifyStartDestination() a fin de usar tu nueva función de extensión en lugar de la aserción larga.
@Test
fun cupcakeNavHost_verifyStartDestination() {
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

Cómo verificar que la pantalla de inicio no tenga un botón Up

El diseño original de la app de Cupcake no tiene un botón Up en la barra de herramientas de la pantalla de inicio.

e6d3d87788ba56c8.png

La pantalla de inicio carece de un botón porque no hay lugar hacia arriba desde esta pantalla, ya que se trata de la inicial. Sigue estos pasos para crear una función que confirme que la pantalla de inicio no tiene un botón Up:

  1. Crea un método llamado cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() y anótalo con @Test.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
}

En Cupcake, el botón Up tiene una descripción de contenido establecida en la string del recurso R.string.back_button.

  1. Crea una variable en la función de prueba con el valor del recurso R.string.back_button.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
   val backText = composeTestRule.activity.getString(R.string.back_button)
}
  1. Confirma que no existe un nodo con esta descripción de contenido en la pantalla.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
   val backText = composeTestRule.activity.getString(R.string.back_button)
   composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist()
}

Cómo verificar la navegación a la pantalla de sabores

Cuando haces clic en uno de los botones de la pantalla de inicio, se activa un método que le indica al controlador de navegación que debe navegar a la pantalla de sabores.

fb8f61896bfa473c.png

En esta prueba, escribirás un comando para hacer clic en un botón a fin de activar esta navegación y verificar que la ruta de destino sea la pantalla de sabores.

  1. Crea una función llamada cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() y anótala con @Test.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen(){
}
  1. Busca el botón One Cupcake por su ID de recurso de strings y realiza una acción de clic en él.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
}
  1. Confirma que el nombre de la ruta actual es el nombre de la pantalla de sabores.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

Cómo escribir más métodos de ayuda

La app de Cupcake tiene un flujo de navegación principalmente lineal. A menos que hagas clic en el botón Cancel, solo podrás navegar por la app en una dirección. Por lo tanto, a medida que pruebes pantallas en un nivel más profundo de la app, podrás repetir el código para navegar a las áreas que quieras probar. Esta situación justifica el uso de más métodos auxiliares de modo que solo tengas que escribir el código una vez.

Ahora que probaste la navegación a la pantalla de sabores, crea un método que navegue a ella, de modo que no tengas que repetir ese código para pruebas futuras.

  1. Crea un método llamado navigateToFlavorScreen().
private fun navigateToFlavorScreen() {
}
  1. Escribe un comando a fin de encontrar el botón One Cupcake y haz una acción de clic en él, como lo hiciste en la sección anterior.
private fun navigateToFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
}

Recuerda que no podrás hacer clic en el botón Next de la pantalla de sabores hasta que se seleccione un sabor. El objetivo de este método solo consiste en preparar la IU para la navegación. Después de llamarlo, la IU debería estar en un estado en el que se pueda hacer clic en el botón Next.

  1. Busca un nodo en la IU con la string R.string.chocolate y realiza una acción de clic en él para seleccionarlo.
private fun navigateToFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
   composeTestRule.onNodeWithStringId(R.string.chocolate)
       .performClick()
}

Verifica si puedes escribir métodos auxiliares que naveguen a las pantallas de retiro y resumen. Prueba este ejercicio por tu cuenta antes de ver la solución.

private fun navigateToPickupScreen() {
   navigateToFlavorScreen()
   composeTestRule.onNodeWithStringId(R.string.next)
       .performClick()
}

private fun navigateToSummaryScreen() {
   navigateToPickupScreen()
   composeTestRule.onNodeWithText(getFormattedDate())
       .performClick()
   composeTestRule.onNodeWithStringId(R.string.next)
       .performClick()
}

A medida que pruebes pantallas más allá de la de inicio, deberás planificar probar la funcionalidad del botón Up para asegurarte de que dirija la navegación a la pantalla anterior. Puedes crear una función auxiliar a los efectos de encontrar el botón Up y hacer clic en él.

private fun performNavigateUp() {
   val backText = composeTestRule.activity.getString(R.string.back_button)
   composeTestRule.onNodeWithContentDescription(backText).performClick()
}

Cómo maximizar la cobertura de las pruebas

El conjunto de pruebas de una app debe probar la mayor cantidad de funciones posible. En un mundo perfecto, un paquete de pruebas de IU abarcaría el 100% de la funcionalidad de la IU. En la práctica, esta cobertura de la prueba es difícil de alcanzar porque existen muchos factores externos a tu app que pueden afectar la IU, como dispositivos con tamaños de pantalla únicos, diferentes versiones del sistema operativo Android y apps de terceros capaces de afectar otras apps del teléfono.

Una forma de ayudar a maximizar la cobertura de las pruebas consiste en escribir pruebas junto con las funciones a medida que las agregas. De esta manera, evitarás la necesidad de adelantarte a las nuevas funciones o de volver atrás para recordar todas las situaciones posibles. En este punto, Cupcake es una app relativamente pequeña, y ya probaste una parte importante de su navegación. Sin embargo, hay más estados de navegación para probar.

Verifica si puedes escribir las pruebas a los efectos de comprobar los siguientes estados de navegación. Intenta implementarlas por tu cuenta antes de ver la solución.

  • Navegación a la pantalla de inicio haciendo clic en el botón Up de la pantalla de sabores
  • Navegación a la pantalla de inicio haciendo clic en el botón Cancel de la pantalla de sabores
  • Navegación a la pantalla de retiro
  • Navegación a la pantalla de sabores haciendo clic en el botón Up de la pantalla de retiro
  • Navegación a la pantalla de inicio haciendo clic en el botón Cancel de la pantalla de retiro
  • Navegación a la pantalla de resumen
  • Navegación a la pantalla de inicio haciendo clic en el botón Cancel de la pantalla de resumen
@Test
fun cupcakeNavHost_clickNextOnFlavorScreen_navigatesToPickupScreen() {
   navigateToFlavorScreen()
   composeTestRule.onNodeWithStringId(R.string.next)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Pickup.name)
}

@Test
fun cupcakeNavHost_clickBackOnFlavorScreen_navigatesToStartOrderScreen() {
   navigateToFlavorScreen()
   performNavigateUp()
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickCancelOnFlavorScreen_navigatesToStartOrderScreen() {
   navigateToFlavorScreen()
   composeTestRule.onNodeWithStringId(R.string.cancel)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickNextOnPickupScreen_navigatesToSummaryScreen() {
   navigateToPickupScreen()
   composeTestRule.onNodeWithText(getFormattedDate())
       .performClick()
   composeTestRule.onNodeWithStringId(R.string.next)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Summary.name)
}

@Test
fun cupcakeNavHost_clickBackOnPickupScreen_navigatesToFlavorScreen() {
   navigateToPickupScreen()
   performNavigateUp()
   navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

@Test
fun cupcakeNavHost_clickCancelOnPickupScreen_navigatesToStartOrderScreen() {
   navigateToPickupScreen()
   composeTestRule.onNodeWithStringId(R.string.cancel)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

@Test
fun cupcakeNavHost_clickCancelOnSummaryScreen_navigatesToStartOrderScreen() {
   navigateToSummaryScreen()
   composeTestRule.onNodeWithStringId(R.string.cancel)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

6. Cómo escribir pruebas para la pantalla de pedidos

La navegación es solo un aspecto de la funcionalidad de la app de Cupcake. El usuario también interactúa con cada una de las pantallas de la app. Debes verificar lo que aparece en estas pantallas y que las acciones realizadas en ellas muestren los resultados correctos. El elemento SelectOptionScreen es una parte importante de la app.

En esta sección, escribirás una prueba a fin de verificar que el contenido de esta pantalla esté configurado correctamente.

Cómo probar el contenido de la pantalla de selección de sabores

  1. Crea una nueva clase dentro del directorio app/src/androidTest llamada CupcakeOrderScreenTest, en la que se encuentran los otros archivos de prueba.

b8d85fba1fabedef.png

  1. En esta clase, crea una AndroidComposeTestRule.
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
  1. Crea una función llamada selectOptionScreen_verifyContent() y anótala con @Test.
@Test
fun selectOptionScreen_verifyContent() {

}

En esta función, configurarás el contenido de la regla de Compose como SelectOptionScreen. De esta manera, se garantiza que el elemento SelectOptionScreen que admite composición se inicie directamente de modo que no se requiera navegación. Sin embargo, esta pantalla necesita dos parámetros: un subtotal y una lista de opciones de sabores.

  1. Crea la lista de sabores y el subtotal que se pasarán a la pantalla.
@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"
}
  1. Configura el contenido en el elemento SelectOptionScreen que admite composición con el CupcakeTheme usando los valores que acabas de crear.

Ten en cuenta que este enfoque es similar al inicio de un elemento que admite composición desde la MainActivity. La única diferencia es que MainActivity llama al elemento CupcakeApp, y aquí llamas al elemento SelectOptionScreen. Poder cambiar el elemento que inicias desde setContent() te permite iniciar elementos específicos que admiten composición, en lugar de hacer que la prueba pase de forma explícita por la app para llegar al área que deseas probar. Este enfoque ayuda a evitar que la prueba falle en áreas del código que no están relacionadas con tu prueba actual.

@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"

   // When SelectOptionScreen is loaded
   composeTestRule.setContent {
       CupcakeTheme {
           SelectOptionScreen(subtotal = subTotal, options = flavours)
       }
   }
}

En este punto de la prueba, la app inicia el elemento SelectOptionScreen que admite composición, lo que luego te permitirá interactuar con él mediante las instrucciones de la prueba.

  1. Itera en la lista de flavours y asegúrate de que cada elemento de la string aparezca en la pantalla.
  2. Usa el método onNodeWithText() a fin de buscar el texto en pantalla y el método assertIsDisplayed() para verificar que este se muestre en la app.
@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"

   // When SelectOptionScreen is loaded
   composeTestRule.setContent {
       CupcakeTheme {
           SelectOptionScreen(subtotal = subTotal, options = flavours)
       }
   }

   // Then all the options are displayed on the screen.
   flavours.forEach { flavour ->
       composeTestRule.onNodeWithText(flavour).assertIsDisplayed()
   }
}
  1. Usa la misma técnica con el fin de comprobar que la app muestre el texto y confirma que esta muestre la string correcta del subtotal en la pantalla. Busca el ID de recurso de R.string.subtotal y el valor correcto del subtotal en la pantalla y, luego, confirma que la app muestra el valor.
@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"

   // When SelectOptionScreen is loaded
   composeTestRule.setContent {
       CupcakeTheme {
           SelectOptionScreen(subtotal = subTotal, options = flavours)
       }
   }

   // Then all the options are displayed on the screen.
   flavours.forEach { flavour ->
       composeTestRule.onNodeWithText(flavour).assertIsDisplayed()
   }
   // And then the subtotal is displayed correctly.
   composeTestRule.onNodeWithText(
      composeTestRule.activity.getString(
          R.string.subtotal_price,
          subTotal
      )
   ).assertIsDisplayed()
}

Recuerda que el botón Next no estará habilitado hasta que se seleccione un elemento. Esta prueba solo verifica el contenido de la pantalla, por lo que lo último que debes probar es que el botón Next esté inhabilitado.

  1. Busca el botón Next mediante el mismo mecanismo para encontrar un nodo por ID de recurso de strings. Sin embargo, en lugar de verificar que la app muestre el nodo, usa el método assertIsNotEnabled().
@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"

   // When SelectOptionScreen is loaded
   composeTestRule.setContent {
       CupcakeTheme {
           SelectOptionScreen(subtotal = subTotal, options = flavours)
       }
   }

   // Then all the options are displayed on the screen.
   flavours.forEach { flavour ->
       composeTestRule.onNodeWithText(flavour).assertIsDisplayed()
   }
   // And then the subtotal is displayed correctly.
   composeTestRule.onNodeWithText(
      composeTestRule.activity.getString(
          R.string.subtotal_price,
          subTotal
      )
   ).assertIsDisplayed()
   // And then the next button is disabled
composeTestRule.onNodeWithText(getString(R.string.next)).assertIsNotEnabled()
}

Cómo maximizar la cobertura de las pruebas

La prueba de contenido de la pantalla de selección de sabores solo prueba un aspecto de una sola pantalla. Puedes escribir varias pruebas adicionales a fin de aumentar la cobertura de código. Intenta escribir las siguientes pruebas por tu cuenta antes de descargar el código de la solución.

  • Verifica el contenido de la pantalla de inicio.
  • Verifica el contenido de la pantalla de resumen.
  • Verifica que el botón Next esté habilitado cuando se seleccione una opción en la pantalla de selección de sabores.

Cuando escribas tus pruebas, ten en cuenta cualquier función auxiliar que pueda reducir la cantidad de código que escribas.

7. Código de solución

8. Resumen

¡Felicitaciones! Aprendiste a probar el componente Navigation de Jetpack. También aprendiste algunas habilidades fundamentales para escribir pruebas de IU, como escribir métodos auxiliares reutilizables, aprovechar setContent() a fin de escribir pruebas concisas, configurar tus pruebas con la anotación @Before y pensar en formas de lograr la máxima cobertura de prueba. A medida que continúes compilando apps para Android, recuerda seguir escribiendo pruebas junto con tu código de funciones.