Automação de apps móveis em dispositivos reais
Construa uma automação de apps móveis fiável em dispositivos reais com Appium, ADB, UIAutomator e XCUITest, além de soluções para instabilidade, paralelização da frota e integração com CI.
A automação de apps móveis em dispositivos reais usa frameworks como Appium, ADB, UIAutomator e XCUITest para conduzir telemóveis físicos através de fluxos repetíveis. Executar sobre hardware real — e paralelizar numa frota — dá-lhe uma cobertura de regressão e um sinal de desempenho que os emuladores não conseguem igualar.
- The core stacks are Appium (cross-platform), UIAutomator/Espresso and ADB (Android), and XCUITest (iOS); scrcpy is invaluable for observing and debugging Android runs.
- Prefer written, versioned scripts over record-and-playback for anything you will maintain; recording is fine for one-off exploration.
- Flakiness is the main enemy — solve it with explicit waits and stable selectors, not sleeps.
- A fleet's value is parallelization: shard suites across devices to keep wall-clock time low.
- Wire automation into CI so every build runs against a real-device core tier.
A pilha de automação
Appium
O Appium é a opção multiplataforma mais comum. Expõe o protocolo W3C WebDriver, pelo que se escrevem os testes na linguagem à escolha e se controla Android e iOS através de uma única API. Por baixo, o Appium delega em motores de automação específicos de cada plataforma — UIAutomator2/Espresso no Android, XCUITest no iOS — obtendo-se assim um controlo nativo com uma interface portátil. É adequado para equipas que querem um único framework e uma única base de testes em todas as plataformas.
ADB (Android Debug Bridge)
O ADB é o canivete suíço do Android. Além de instalar e iniciar apps, executa ações ao nível da shell: conceder permissões, configurar rede e idioma, simular eventos de entrada, capturar o logcat, extrair capturas de ecrã, alternar o modo avião e preparar condições para os testes. A maior parte da automação em Android apoia-se no ADB para a configuração inicial, a limpeza final e o controlo do estado do dispositivo, mesmo quando o controlo da UI é feito através de outro framework.
UIAutomator e Espresso
Para equipas que trabalham só com Android, o Espresso (em processo, de caixa branca, rápido e estável) cobre a UI da própria app, enquanto o UIAutomator trata das interações entre apps e com a UI do sistema (notificações, diálogos de permissões, definições). São frequentemente usados em conjunto.
XCUITest
O XCUITest é o framework nativo de UI da Apple, executado através do Xcode. É a via mais fiável para a automação de UI em iOS e é o que o Appium usa por baixo no iOS. Para o comportamento específico de cada plataforma e as diferenças de configuração, consulte frotas de iOS vs Android.
scrcpy
O scrcpy espelha e controla um dispositivo Android por USB ou TCP/IP com baixa latência. Não é um framework de testes, mas é a forma mais rápida de observar uma execução automatizada, reproduzir uma falha de forma interativa e depurar seletores em direto.
| Appium (cross-platform) | Native (Espresso / XCUITest) | |
|---|---|---|
| Codebase | One test suite, both platforms | Separate suite per platform |
| Speed & stability | Good, one layer of indirection | Fastest, most stable on its platform |
| System UI access | Via UIAutomator delegation | Direct (UIAutomator/XCUITest) |
| Best fit | Small team, shared flows | Platform-specific team, max reliability |
Script versus gravação
As ferramentas de gravação e reprodução geram um script capturando os seus toques. São atrativas para um primeiro rascunho ou uma verificação pontual, mas os scripts gravados tendem a ser frágeis: fixam coordenadas ou seletores pouco robustos e não têm a estrutura necessária para se manterem à escala.
Os scripts escritos à mão são a melhor opção para tudo o que seja duradouro. Permitem usar localizadores estáveis (IDs de acessibilidade, IDs de recursos), extrair passos reutilizáveis, parametrizar dados, adicionar asserções e manter tudo sob controlo de versões junto com a app. Um caminho intermédio prático é gravar para explorar e depois reescrever os fluxos úteis como código sustentável, com seletores e esperas adequados.
Combater a instabilidade e a sincronização
Os testes instáveis destroem a confiança numa suite. Em dispositivos reais os tempos são genuinamente variáveis — a latência de rede, as animações e a carga em segundo plano oscilam todas —, pelo que a solução é uma sincronização disciplinada.
- Nunca use esperas fixas como mecanismo de espera principal. Substitua-as por esperas explícitas que verificam uma condição (elemento presente, visível, ativado) até um tempo limite.
- Use seletores estáveis. Prefira os identificadores de acessibilidade e os IDs de recursos a um XPath por texto ou índice, que se quebra com alterações de conteúdo e de layout.
- Espere pelo estado da app, não pelo relógio. As condições de inatividade, os sinais de quiescência de rede e os estados dos elementos são mais fiáveis do que adivinhar uma duração.
- Controle o ambiente. Reinicie o estado da app entre testes, semeie dados conhecidos, desative as animações sempre que possível e fixe o idioma/fuso horário para que as execuções sejam determinísticas.
- Coloque em quarentena e repita com critério. Isole os testes conhecidos por serem instáveis, adicione repetições limitadas para os passos genuinamente não determinísticos e acompanhe as taxas de falhas intermitentes para corrigir as causas raiz em vez de as mascarar.
Paralelização numa frota
Um único dispositivo executa os testes em série; uma frota executa-os em paralelo. Esta é a principal razão para automatizar sobre hardware físico a grande escala.
O sharding divide o conjunto de testes entre dispositivos, de modo que o tempo total diminui de forma aproximadamente linear com o número de dispositivos. Pode fazer sharding por teste (distribuindo os casos de forma uniforme) ou por célula de matriz (cada dispositivo fica responsável por uma combinação de SO/modelo dos seus níveis de cobertura).
Requisitos práticos para execuções paralelas limpas:
| Aspeto | Abordagem |
|---|---|
| Endereçamento de dispositivos | IDs/números de série estáveis por dispositivo; um registo que associa dispositivos a capacidades |
| Isolamento | Uma sessão por dispositivo; reinício do estado da app entre execuções |
| Alocação | Um agendador que cede dispositivos livres a tarefas e evita reservas duplicadas |
| Fiabilidade | Verificações de saúde para que os dispositivos inativos ou offline sejam ignorados, e não contados como falha |
Coordenar cedências, filas e escalonamento é tarefa de uma camada de orquestração — consulte agendamento e orquestração. Manter os dispositivos suficientemente saudáveis para confiar nos resultados é abordado em monitorização e saúde da frota.
Integração com CI
A automação gera valor quando é executada automaticamente. O padrão típico:
- Compilar o artefacto da app em CI.
- Aprovisionar um dispositivo da frota através do agendador (ceder um dispositivo do nível principal que corresponda à célula de matriz alvo).
- Instalar e executar a suite no dispositivo cedido.
- Recolher artefactos — registos (logcat/syslog), capturas de ecrã ou vídeo, e um relatório de testes estruturado.
- Bloquear o pipeline com base no nível principal; executar uma cobertura mais ampla numa cadência noturna ou pré-lançamento para manter o feedback dos PR rápido.
Mantenha o aprovisionamento de dispositivos sob a responsabilidade do agendador em vez de fixar números de série no pipeline, para que os trabalhos de CI se coloquem em fila de forma ordenada quando os dispositivos estão ocupados e nunca colidam.
Regra geral: bloqueie cada build com uma suite do nível principal pequena, rápida e estável. Deixe a matriz ampla e lenta para execuções noturnas ou de lançamento. Isto mantém o feedback aos programadores ágil sem sacrificar a cobertura.