Automatizar testes de interface

O teste de interações do usuário ajuda a garantir que os usuários não encontrem resultados inesperados ou tenham uma experiência ruim ao interagir com o app. Crie o hábito de criar testes de interface do usuário (interface) se precisar verificar se a interface do app está funcionando corretamente.

Uma abordagem para o teste de IU é fazer com que um testador humano realize um conjunto de operações do usuário no aplicativo de destino e verificar se ele está se comportando corretamente. No entanto, essa abordagem manual pode ser demorada e propensa a erros. Uma abordagem mais eficiente é programar seus testes de interface para que as ações do usuário sejam realizadas de maneira automatizada. A abordagem automatizada permite executar os testes de maneira rápida, confiável e repetida.

Os testes de interface iniciam um app (ou parte dele), simulam as interações do usuário e, por fim, verificam se o app reagiu corretamente. Eles são testes de integração que podem variar de verificar o comportamento de um pequeno componente a um teste de navegação grande que percorre todo um fluxo de usuário. Elas são úteis para verificar regressões e a compatibilidade com diferentes níveis de API e dispositivos físicos.

Testes de interface instrumentados no Android Studio

Para executar testes de interface instrumentados no Android Studio, implemente o código de teste em uma pasta de teste separada do Android: src/androidTest/java. O plug-in do Android para Gradle cria um app de teste com base no código e carrega esse app no mesmo dispositivo que o app de destino. No código de teste, você pode usar frameworks de teste da interface para simular interações do usuário no app de destino e executar tarefas de teste que abrangem cenários de uso específicos.

Frameworks do Jetpack

O Jetpack inclui vários frameworks que oferecem APIs para criar testes de interface:

  • O framework de teste Espresso (Android 4.0.1, API de nível 14 ou mais recente) oferece APIs para programar testes de interface para simular interações do usuário com Views em um único app de destino. Um principal benefício de usar o Espresso é que ele fornece sincronização automática de ações de teste com a IU do app que você está testando. O Espresso detecta quando a linha de execução principal está inativa. Assim, é possível executar os comandos de teste no momento adequado, melhorando a confiabilidade dos testes.
  • O Jetpack Compose (Android 5.0, API de nível 21 ou mais recente) oferece um conjunto de APIs de teste para iniciar e interagir com telas e componentes do Compose. As interações com elementos do Compose são sincronizadas com testes e têm controle total sobre o tempo, as animações e as recomposições.
  • O UI Automator (Android 4.3, API de nível 18 ou mais recente) é um framework de teste de interface adequado para testes funcionais da interface entre apps em apps instalados e do sistema. As APIs UI Automator permitem executar operações como abrir o menu "Configurações" ou o Acesso rápido aos apps em um dispositivo de teste.
  • O Robolectric (Android 4.1, API de nível 16 ou mais recente) permite criar testes locais que são executados na estação de trabalho ou no ambiente de integração contínua em uma JVM normal, em vez de em um emulador ou dispositivo. Ele pode usar as APIs de teste do Espresso ou do Compose para interagir com componentes da interface.

Inconsistência e sincronização

A natureza assíncrona dos aplicativos e frameworks para dispositivos móveis muitas vezes dificulta a criação de testes confiáveis e repetíveis. Quando um evento de usuário é injetado, o framework de teste precisa esperar que o app termine de reagir a ele, o que pode variar de alterar um texto na tela para uma recriação completa de uma atividade. Quando um teste não tem um comportamento determinístico, ele é instável.

Frameworks modernos, como o Compose ou o Espresso, foram criados pensando nos testes. Por isso, há uma certa garantia de que a interface vai ficar inativa antes da próxima ação ou declaração de teste. Isso é a sincronização.

Testar a sincronização

Problemas ainda podem surgir quando você executa operações assíncronas ou em segundo plano desconhecidas para o teste, como carregar dados de um banco de dados ou mostrar animações infinitas.

Diagrama de fluxo com uma repetição que verifica se o app está inativo antes de fazer um teste
Figura 1: sincronização de teste.

Para aumentar a confiabilidade do seu conjunto de testes, instale uma maneira de rastrear operações em segundo plano, como os Recursos do Espresso Idling. Além disso, é possível substituir módulos para versões de teste que você pode consultar para inatividade ou melhorar a sincronização, como TestDispatcher para corrotinas ou RxIdler para RxJava.

Diagrama mostrando uma falha no teste quando a sincronização é baseada na espera por um tempo fixo
Figura 2: o uso do sono nos testes leva a testes lentos ou instáveis.

Configuração de arquitetura e teste

A arquitetura do app precisa permitir que os testes substituam partes dele para testes duplos, e você precisa usar bibliotecas que forneçam utilitários para ajudar nos testes. Por exemplo, é possível substituir um módulo de repositório de dados por uma versão na memória que forneça dados determinísticos e falsos para o teste.

Diagramas de arquitetura de produção e teste. O diagrama de produção mostra fontes de dados locais e remotas fornecendo dados ao repositório, que, por sua vez, os fornece de maneira assíncrona à interface. O diagrama de teste mostra um repositório simulado que fornece dados de maneira síncrona com a interface.
Figura 3: como testar uma IU substituindo as dependências por cópias.

A abordagem recomendada para ativar essa funcionalidade é usar a injeção de dependência. É possível criar seu próprio sistema manualmente, mas recomendamos usar um framework de DI como o Hilt para isso.

Por que testar automaticamente?

Um app Android pode ser destinado a milhares de dispositivos diferentes em vários níveis de API e formatos, e o alto nível de personalização que o SO oferece ao usuário significa que seu app pode ser renderizado incorretamente ou até mesmo falhar em alguns dispositivos.

Os testes de interface permitem fazer testes de compatibilidade, verificando o comportamento de um app em diferentes contextos. É recomendável executar testes de interface em dispositivos que variam das seguintes maneiras:

  • Nível da API: 21, 25 e 30.
  • Localidade: inglês, árabe e chinês.
  • Orientação: retrato, paisagem.

Além disso, os apps devem verificar o comportamento além dos smartphones. É necessário testar em tablets, dobráveis e outros dispositivos.

Outros recursos

Para saber mais sobre como criar testes de interface, consulte os recursos a seguir.

Documentação

Codelabs