Conceitos básicos para testes de apps Android

Esta página descreve os princípios básicos para testar apps Android, incluindo os práticas recomendadas centrais e seus benefícios.

Benefícios dos testes

Os testes são uma parte importante do processo de desenvolvimento de apps. Executando testes com seu app de forma consistente, você pode verificar a precisão, a funcionalidade comportamento e usabilidade dele antes de liberá-lo para o público.

Você pode testar seu app manualmente em navegação. Você pode usar dispositivos e emuladores diferentes, mudar o idioma do sistema e tentar gerar cada erro do usuário ou por todos os fluxos de usuários.

No entanto, o teste manual tem pouca escala e pode ser fácil de ignorar. regressões no comportamento do app. Os testes automatizados envolvem o uso de ferramentas. que realizam testes para você, o que é mais rápido, mais repetível e geralmente dá a você um feedback mais acionável sobre seu aplicativo no início do desenvolvimento de desenvolvimento de software.

Tipos de testes no Android

Aplicativos para dispositivos móveis são complexos e precisam funcionar bem em muitos ambientes. Conforme Há muitos tipos de testes.

Assunto

Por exemplo, há diferentes tipos de teste dependendo do assunto:

  • Teste funcional: o app faz o que deve fazer?
  • Teste de desempenho: ele faz isso de maneira rápida e eficiente?
  • Teste de acessibilidade: ele funciona bem com os serviços de acessibilidade?
  • Teste de compatibilidade: funciona bem em todos os dispositivos e níveis de API?

Escopo

Os testes também variam de acordo com o tamanho ou grau de isolamento:

  • Testes de unidade ou pequenos testes verificam apenas uma parte muito pequena do app. como um método ou uma classe.
  • Testes completos ou grandes testes verificam partes maiores do app na ao mesmo tempo, como uma tela inteira ou um fluxo de usuário.
  • Os testes médios são intermediários e verificam a integração entre dois ou mais unidades.
.
Os testes podem ser pequenos, médios ou grandes.
Figura 1: escopos de teste em um aplicativo típico.

Há muitas maneiras de classificar testes. No entanto, a distinção mais importante para desenvolvedores de apps é onde os testes são executados.

Diferenças entre testes instrumentados e locais

É possível executar testes em um dispositivo Android ou em outro computador:

  • Os testes instrumentados são executados em um dispositivo Android, físico ou emulado. O app é criado e instalado junto com um app de teste que injeta comandos e lê o estado. Os testes instrumentados geralmente são testes de IU, inicialização de apps e e interagir com ele.
  • Os testes locais são executados na máquina de desenvolvimento ou em um servidor, também chamados de testes do lado do host. Elas geralmente são pequenas e rápidas, isolando o objeto em teste no restante do app.
.
Os testes podem ser executados como testes instrumentados em um dispositivo ou como testes locais na máquina de desenvolvimento.
Figura 2: tipos diferentes de testes dependendo de onde eles são executados.

Nem todos os testes de unidade são locais e nem todos os testes completos são executados em um dispositivo. Por exemplo:

  • Teste local grande: você pode usar um simulador do Android executado localmente, como como Robolectric.
  • Teste de instrumentação pequeno: você pode verificar se o código funciona bem com uma recurso de framework, como um banco de dados SQLite. É possível executar esse teste vários dispositivos para verificar a integração com várias versões do SQLite.

Exemplos

Os snippets a seguir demonstram como interagir com a interface em uma teste de interface instrumentado que clica em um elemento e verifica se outro é exibido.

Espresso

// When the Continue button is clicked
onView(withText("Continue"))
    .perform(click())

// Then the Welcome screen is displayed
onView(withText("Welcome"))
    .check(matches(isDisplayed()))

IU do Compose

// When the Continue button is clicked
composeTestRule.onNodeWithText("Continue").performClick()

// Then the Welcome screen is displayed
composeTestRule.onNodeWithText("Welcome").assertIsDisplayed()

Este snippet mostra parte de um teste de unidade para um ViewModel (local, lado do host) teste):

// Given an instance of MyViewModel
val viewModel = MyViewModel(myFakeDataRepository)

// When data is loaded
viewModel.loadData()

// Then it should be exposing data
assertTrue(viewModel.data != null)

Como definir uma estratégia de teste

Em um mundo ideal, você testaria todas as linhas de código do app em todos os dispositivos com que o app é compatível. Infelizmente, essa abordagem é muito lenta e caro para ser prático.

Uma boa estratégia de teste encontra um equilíbrio apropriado entre a fidelidade de um de teste, velocidade e confiabilidade. A semelhança do ambiente de teste com um dispositivo real determina a fidelidade do teste. Os testes de maior fidelidade são executados dispositivos emulados ou o próprio dispositivo físico. Testes de menor fidelidade podem ser executados na JVM da estação de trabalho local. Testes de alta fidelidade costumam ser mais lentos e exigem mais recursos, então nem todo teste deve ser de alta fidelidade.

Testes instáveis

Erros ocorrem mesmo em execuções de teste projetadas e implementadas corretamente. Por exemplo: ao executar um teste em um dispositivo real, uma atualização automática pode começar no meio de um teste e causar a falha dele. Disputas sutis no código podem ocorrer em apenas uma pequena porcentagem das vezes. Os testes que não passarem em 100% dos tempo são instáveis.

Arquitetura testável

Com uma arquitetura de app testável, o código segue uma estrutura que permite para testar facilmente partes diferentes dele de forma isolada. Arquiteturas testáveis têm e outras vantagens, como melhor legibilidade, facilidade de manutenção, reutilização.

Uma arquitetura não testável produz o seguinte:

  • Testes maiores, mais lentos e mais instáveis. As classes que não podem ser testadas por unidade podem ter sejam cobertos por testes de integração ou de interface maiores.
  • Menos oportunidades para testar cenários diferentes. Testes maiores são mais lentos, então testar todos os estados possíveis de um app pode ser inviável.

Para saber mais sobre as diretrizes de arquitetura, consulte o guia do app do Terraform.

Abordagens de desacoplamento

Se você puder extrair parte de uma função, classe ou módulo do resto, testar mais fácil e eficaz. Essa prática é conhecida como dissociação é o conceito mais importante para a arquitetura testável.

Confira algumas técnicas comuns de dissociação:

  • Divida um app em camadas, como "Apresentação", "Domínio" e "Dados". Você pode também dividem o app em módulos, um por recurso.
  • Evite adicionar lógica a entidades que têm dependências grandes, como atividades e fragmentos. Use essas classes como pontos de entrada para o framework e mover a interface e a lógica de negócios para outro lugar, como para um elemento combinável, ViewModel ou camada de domínios.
  • Evite dependências de framework diretas em classes que contêm lógica de negócios. Por exemplo, não use contextos do Android em ViewModels.
  • Facilite a substituição das dependências. Por exemplo, use interfaces em vez de implementações concretas. Usar Injeção de dependência, mesmo que você não use um framework de DI.

Próximas etapas

Agora que você sabe por que testar e os dois tipos principais de testes, é possível leia O que testar.

Como alternativa, se quiser criar seu primeiro teste e aprender na prática, marque os codelabs de teste.