Testar o app Cupcake

Mantenha tudo organizado com as coleções Salve e categorize o conteúdo com base nas suas preferências.

1. Introdução

No codelab Navegar entre telas com o Compose, você aprendeu a adicionar navegação a um app do Compose usando o componente de navegação do Jetpack com o Compose.

O app Cupcake tem várias telas para navegar e uma variedade de ações que podem ser realizadas pelo usuário. Esse app é uma ótima oportunidade para você aprimorar suas habilidades de realizar testes automatizados. Neste codelab, você vai criar vários testes de IU para o app Cupcake e aprender a abordar a maximização da cobertura dos testes.

Pré-requisitos

O que você vai aprender

  • Testar o componente de navegação do Jetpack com o Compose.
  • Criar um estado de IU consistente para cada teste de IU.
  • Criar funções auxiliares para testes.

O que você vai criar

  • Testes de IU para o app Cupcake

O que é necessário

  • A versão mais recente do Android Studio.
  • Conexão de Internet para fazer o download do código inicial.

2. Fazer o download do código inicial

  1. No Android Studio, abra a pasta basic-android-kotlin-compose-training-cupcake.
  2. Abra o código do app Cupcake no Android Studio.

3. Configurar o Cupcake para testes de IU

Adicionar a dependência androidTest

A ferramenta de build do Gradle permite adicionar dependências a módulos específicos. Essa funcionalidade impede que as dependências sejam compiladas desnecessariamente. Você já está familiarizado com a configuração implementation ao incluir dependências em um projeto, porque usou essa palavra-chave para importar dependências no arquivo build.gradle do módulo do app. Usar a palavra-chave implementation disponibiliza essa dependência para todos os conjuntos de origem nesse módulo. A essa altura do curso, você ganhou experiência com os conjuntos de origem main, test e androidTest.

Os testes de IU estão nos próprios conjuntos de origem chamados androidTest. As dependências necessárias apenas para este módulo não precisam ser compiladas para outros módulos, como o módulo main, em que o código do app está incluído. Ao adicionar uma dependência usada apenas por testes de IU, use a palavra-chave androidTestImplementation para declarar a dependência no arquivo build.gradle do módulo do app. Isso garante que as dependências de teste da IU sejam compiladas somente quando você executar testes de IU.

Para adicionar as dependências necessárias e criar testes de IU, siga estas etapas:

  1. Abra o arquivo app/build.gradle.
  2. Adicione as seguintes dependências à seção de dependências do arquivo:
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"

Criar o diretório de testes de IU

  1. Com o botão direito do mouse, clique no diretório src na visualização do projeto e selecione New > Directory.

288ebc5eae5fba2e.png

  1. Selecione a opção androidTest/java.

12ec57f9d9e907de.png

Criar o pacote de teste

  1. Com o botão direito do mouse, clique no diretório androidTest/java na janela do projeto e selecione New > Package.

5104da51d0529eb7.png

  1. Dê o nome com.example.cupcake.test. da0e0458fdcb1cfc.png ao pacote.

Criar a classe de teste de navegação

No diretório test, crie uma nova classe Kotlin com o nome CupcakeScreenNavigationTest.

7336dbed4e215b68.png

4. Configurar o host de navegação

Em um codelab anterior, você aprendeu que os testes de IU no Compose exigem uma regra de teste. O mesmo acontece no teste da navegação do Jetpack. No entanto, testar a navegação exige algumas configurações adicionais na regra de teste do Compose.

Ao testar a navegação no Compose, você não vai ter acesso ao mesmo NavHostController usado no código do app. No entanto, é possível usar um TestNavHostController e configurar a regra de teste com esse controlador de navegação. Nesta seção, você vai aprender a configurar e reutilizar a regra para testes de navegação.

  1. Em CupcakeScreenNavigationTest.kt, crie uma regra de teste usando createAndroidComposeRule e transmitindo ComponentActivity como o parâmetro de tipo.
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()

Para garantir que seu app navegue para o lugar correto, é necessário referenciar uma instância TestNavHostController para verificar a rota de navegação do host de navegação quando o app realiza ações para navegar.

  1. Crie uma instância TestNavHostController como uma variável lateinit. No Kotlin, a palavra-chave lateinit é usada para declarar uma propriedade que pode ser inicializada após a declaração do objeto.
private lateinit var navController: TestNavHostController

Em seguida, especifique o elemento de composição que você quer usar nos testes de IU.

  1. Crie um método com o nome setupCupcakeNavHost().
  2. No método setupCupcakeNavHost(), chame o método setContent() na regra de teste do Compose que você criou.
  3. No lambda transmitido ao método setContent(), chame o elemento de composição CupcakeApp().
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       CupcakeApp()
   }
}

Agora você precisa criar o objeto TestNavHostContoller na classe de teste. Você vai usar esse objeto mais tarde para determinar o estado da navegação, porque o app usa o controlador para navegar pelas várias telas no app Cupcake.

  1. Configure o host de navegação usando o lambda criado anteriormente. Inicialize a variável navController criada, registre um navegador e transmita esse TestNavHostController para o elemento de composição CupcakeApp.
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       navController =
           TestNavHostController(LocalContext.current)
       navController.navigatorProvider.addNavigator(
           ComposeNavigator()
       )
       CupcakeApp(navController = navController)
   }
}

Cada teste na classe CupcakeScreenNavigationTest envolve o teste de um aspecto da navegação. Portanto, cada teste depende do objeto TestNavHostController criado. Em vez de ter que chamar manualmente a função setupCupcakeNavHost() para cada teste a fim de configurar o controlador de navegação, isso pode acontecer automaticamente usando a anotação @Before fornecida pela biblioteca junit. Quando um método é anotado com @Before, ele é executado antes de todos os métodos anotados com @Test.

  1. Adicione a anotação @Test ao método setupCupcakeNavHost().
@Before
fun setupCupcakeNavHost() {
   composeTestRule.setContent {
       navController =
           TestNavHostController(LocalContext.current)
       navController.navigatorProvider.addNavigator(
           ComposeNavigator()
       )
       CupcakeApp(navController = navController)
   }
}

5. Criar testes de navegação

Verificar o destino inicial

Lembre que, ao criar o app Cupcake, você criou uma classe enum chamada Cupcake que continha constantes para ditar a navegação do 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)
}

Todos os apps que têm uma IU têm uma tela inicial de algum tipo. Para o Cupcake, essa tela é Start Order. O controlador de navegação no elemento de composição CupcakeApp usa o item Start da enumeração CupcakeScreen para determinar quando navegar até essa tela. Quando o app for iniciado, se não houver uma rota de destino, a rota de destino do host de navegação vai ser definida como Cupcake.Start.name.

Primeiro, faça um teste para verificar se a tela Start Order é a rota de destino atual quando o app é iniciado.

  1. Crie uma função com o nome cupcakeNavHost_verifyStartDestination() e use a anotação @Test.
@Test
fun cupcakeNavHost_verifyStartDestination() {
}

Agora, você precisa confirmar que a rota de destino inicial do controlador de navegação é a tela "Start Order".

  1. Verifique se o nome da rota esperada, que neste caso é Cupcake.Start.name, é igual à rota de destino da entrada da backstack atual do controlador de navegação.
import org.junit.Assert.assertEquals
...

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

Criar um método auxiliar

Os testes de IU geralmente exigem a repetição de etapas para colocar a IU em um estado em que uma parte específica dela possa ser testada. Uma IU personalizada também pode exigir declarações complexas que precisam ter várias linhas de código. A declaração que você criou na seção anterior exige muito código, e você está usando essa mesma declaração várias vezes enquanto testa a navegação no app Cupcake. Nessas situações, a criação de métodos auxiliares em testes evita criar código duplicado.

Para cada teste de navegação que você criar, use a propriedade name dos itens de enumeração CupcakeScreen para verificar se a rota de destino atual do controlador de navegação está correta. Crie uma função auxiliar que possa ser chamada sempre que você quiser fazer essa declaração.

Conclua as etapas a seguir para criar essa função auxiliar:

  1. Crie um arquivo Kotlin vazio no diretório test chamado ScreenAssertions.

ac62e5b9b8153027.png

  1. Adicione uma função de extensão com o nome assertCurrentRouteName() à classe NavController e transmita uma string para o nome da rota esperada na assinatura do método.
fun NavController.assertCurrentRouteName(expectedRouteName: String) {

}
  1. Nessa função, declare que o expectedRouteName é igual à rota de destino da entrada da backstack atual do controlador de navegação.
import org.junit.Assert.assertEquals
...

fun NavController.assertCurrentRouteName(expectedRouteName: String) {
   assertEquals(expectedRouteName, currentBackStackEntry?.destination?.route)
}
  1. Abra o arquivo CupcakeScreenNavigationTest e modifique a função cupcakeNavHost_verifyStartDestination() para usar a nova função de extensão em vez da declaração longa.
@Test
fun cupcakeNavHost_verifyStartDestination() {
   navController.assertCurrentRouteName(CupcakeScreen.Start.name)
}

Verificar se a tela inicial não tem um botão "Up"

O design original do app Cupcake não tem um botão "Up" na barra de ferramentas da tela inicial.

e6d3d87788ba56c8.png

A tela inicial não tem um botão porque não há nenhum lugar para navegar nessa direção, já que é a tela inicial. Siga estas etapas para criar uma função que confirme que a tela inicial não tem um botão "Up":

  1. Crie um método com o nome cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() e use a anotação @Test.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
}

No app Cupcake, o botão "Up" tem uma descrição de conteúdo definida para a string do recurso R.string.back_button.

  1. Crie uma variável na função de teste com o valor do recurso R.string.back_button.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
   val backText = composeTestRule.activity.getString(R.string.back_button)
}
  1. Afirme que não existe um nó com esta descrição de conteúdo na tela.
@Test
fun cupcakeNavHost_verifyBackNavigationNotShownOnStartOrderScreen() {
   val backText = composeTestRule.activity.getString(R.string.back_button)
   composeTestRule.onNodeWithContentDescription(backText).assertDoesNotExist()
}

Verificar a navegação para a tela "Flavor"

Ao clicar em um dos botões na tela inicial, um método que instrui o controlador de navegação a navegar até a tela "Flavor" é acionado.

fb8f61896bfa473c.png

Neste teste, você vai criar um comando para clicar em um botão e acionar a navegação, além de verificar se o trajeto de destino é a tela "Flavor".

  1. Crie uma função com o nome cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() e use a anotação @Test.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen(){
}
  1. Localize o botão One Cupcake pelo ID do recurso de string e execute uma ação de clique nele.
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
}
  1. Afirme que o nome atual do trajeto é o nome da tela "Flavor".
@Test
fun cupcakeNavHost_clickOneCupcake_navigatesToSelectFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
   navController.assertCurrentRouteName(CupcakeScreen.Flavor.name)
}

Criar mais métodos auxiliares

O app Cupcake tem um fluxo de navegação basicamente linear. Sem clicar no botão Cancel, só é possível navegar pelo app em uma direção. Portanto, ao testar telas mais profundas no app, você pode repetir o código para navegar até as áreas que quer testar. Essa situação merece o uso de mais métodos auxiliares para que você só precise criar esse código uma vez.

Agora que você testou a navegação para a tela "Flavor", crie um método que acesse essa tela para não precisar repetir esse código em testes futuros.

  1. Crie um método com o nome navigateToFlavorScreen().
private fun navigateToFlavorScreen() {
}
  1. Programe um comando para encontrar o botão One Cupcake e execute uma ação de clique, como você fez na seção anterior.
private fun navigateToFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
}

Lembre-se de que o botão Next na tela "Flavor" não é clicável até que um sabor seja selecionado. Esse método serve apenas para preparar a IU para navegação. Depois de chamar esse método, a IU precisa estar em um estado em que o botão Next possa ser clicado.

  1. Encontre um nó na IU com a string R.string.chocolate e execute uma ação de clique nele para o selecionar.
private fun navigateToFlavorScreen() {
   composeTestRule.onNodeWithStringId(R.string.one_cupcake)
       .performClick()
   composeTestRule.onNodeWithStringId(R.string.chocolate)
       .performClick()
}

Tente criar métodos auxiliares que naveguem até a tela "Pickup" e a de resumo. Faça este exercício por conta própria antes de ver a solução.

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

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

Ao testar outras telas, além da tela inicial, você também deve testar a funcionalidade do botão "Up" para garantir que ele direcione a navegação para a tela anterior. Você pode criar uma função auxiliar para encontrar e clicar no botão "Up".

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

Maximizar a cobertura de testes

O pacote de testes de um app precisa testar o máximo de funcionalidades possível. No mundo ideal, um pacote de testes de IU iria abranger 100% da funcionalidade da IU. Na prática, é difícil atingir essa quantidade de cobertura de testes, porque há muitos fatores externos ao app que podem afetar a IU. Por exemplo, dispositivos com tamanhos de tela únicos, versões diferentes do sistema operacional Android e apps de terceiros que podem afetar outros apps no smartphone.

Uma maneira de ajudar a maximizar a cobertura de testes é gravando os testes com os recursos à medida que você os adiciona. Assim, você evita antecipar os novos recursos e ter que se lembrar de todos os cenários possíveis. O Cupcake é um app bem pequeno no momento, e você já testou uma parte significativa da navegação dele. No entanto, há mais estados de navegação para testar.

Veja se é possível programar os testes para verificar os estados de navegação a seguir. Tente implementar por conta própria antes de ver a solução.

  • Navegue até a tela inicial clicando no botão "Up" na tela "Flavor".
  • Navegue até a tela inicial clicando no botão "Cancel" na tela "Flavor".
  • Navegue até a tela "Pickup".
  • Acesse a tela "Flavor" clicando no botão "Up" na tela "Pickup".
  • Navegue até a tela inicial clicando no botão "Cancel" na tela "Pickup".
  • Navegue até a tela "Summary".
  • Navegue até a tela inicial clicando no botão "Cancel" na tela "Summary".
@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. Criar testes para a tela "Order"

A navegação é apenas um aspecto da funcionalidade do app Cupcake. O usuário também interage com cada uma das telas do app. Você precisa verificar o que aparece nessas telas e se as ações realizadas nelas geram os resultados corretos. A tela SelectOptionScreen é uma parte importante do app.

Nesta seção, você vai criar um teste para verificar se o conteúdo dessa tela está definido corretamente.

Testar o conteúdo da tela de escolha do sabor

  1. Crie uma nova classe dentro do diretório app/src/androidTest, chamada CupcakeOrderScreenTest, em que os outros arquivos de teste estão contidos.

b8d85fba1fabedef.png

  1. Nesta classe, crie uma AndroidComposeTestRule.
@get:Rule
val composeTestRule = createAndroidComposeRule<ComponentActivity>()
  1. Crie uma função com o nome selectOptionScreen_verifyContent() e use a anotação @Test.
@Test
fun selectOptionScreen_verifyContent() {

}

Nessa função, o conteúdo da regra do Compose é definido para a SelectOptionScreen. Isso garante que o elemento de composição SelectOptionScreen seja iniciado diretamente para que a navegação não seja necessária. No entanto, essa tela exige dois parâmetros: um subtotal e uma lista de opções de sabor.

  1. Crie uma lista de sabores e um subtotal a ser transmitido para a tela.
@Test
fun selectOptionScreen_verifyContent() {
   // Given list of options
   val flavours = listOf("Vanilla", "Chocolate", "Hazelnut", "Cookie", "Mango")
   // And sub total
   val subTotal = "$100"
}
  1. Defina o conteúdo como o elemento de composição SelectOptionScreen com o CupcakeTheme usando os valores que você acabou de criar.

Essa abordagem é semelhante à inicialização de um elemento de composição da MainActivity. A única diferença é que MainActivity chama o elemento CupcakeApp, e aqui você está chamando o elemento SelectOptionScreen. A possibilidade de mudar o elemento de composição que você inicia no setContent() permite iniciar elementos específicos, em vez de fazer o teste explicitamente pelo app para chegar à área que você quer testar. Essa abordagem ajuda a evitar que o teste falhe em áreas do código que não estejam relacionadas ao teste atual.

@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)
       }
   }
}

Nesse momento do teste, o app inicia o elemento de composição SelectOptionScreen e você pode interagir com ele pelas instruções de teste.

  1. Itere a lista flavours e verifique se cada item de string na lista é mostrado na tela.
  2. Use o método onNodeWithText() para encontrar o texto na tela e use o método assertIsDisplayed() para verificar se o texto é mostrado no 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. Para usar a mesma técnica para verificar se o app mostra o texto, confira se ele mostra a string correta de subtotal na tela. Pesquise na tela o ID do recurso R.string.subtotal e o valor subtotal correto e, em seguida, declare que o app mostra o 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()
}

Lembre-se de que o botão Next só é ativado quando um item é selecionado. Esse teste verifica apenas o conteúdo da tela. Portanto, o último teste a ser feito é se o botão Next está desativado.

  1. Para encontrar o botão Next, use a mesma abordagem para encontrar um nó por ID de recurso de string. No entanto, em vez de verificar se o app mostra o nó, use o 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()
}

Maximizar a cobertura de testes

O teste do conteúdo da tela de escolha do sabor mostra apenas um aspecto de uma única tela. Há diversos outros testes que você pode criar para aumentar a cobertura do código. Tente criar os testes a seguir por conta própria antes de fazer o download do código da solução.

  • Verifique o conteúdo da tela inicial.
  • Verifique o conteúdo da tela "Summary".
  • Verifique se o botão Next é ativado quando uma opção é selecionada na tela de escolha do sabor.

Ao criar os testes, lembre-se das funções auxiliares que podem reduzir a quantidade de código que você precisa criar.

7. Código da solução

8. Resumo

Parabéns! Você aprendeu a testar o componente de navegação do Jetpack. Você também aprendeu algumas habilidades fundamentais para criar testes de IU, por exemplo, criar métodos auxiliares reutilizáveis, usar o setContent() para criar testes concisos, configurar seus testes com a anotação @Before e pensar na máxima cobertura de testes. Ao continuar criando apps Android, continue programando testes junto com seu código de recursos.