Os testes de UI verificam a corretude da exibição e interação dos elementos da interface do usuário de um aplicativo móvel — botões, campos de texto, listas e componentes de navegação. Diferente dos testes unitários que verificam a lógica de negócios, os testes de UI simulam ações do usuário: toques, deslizes, entrada de texto e verificam a resposta da interface. De acordo com um estudo da Android Developers, 2024, os testes de UI cobrem 70% dos cenários críticos de usuário e permitem detectar defeitos de layout que não são acessíveis para verificações lógicas.
Principais pontos
Os testes de UI são um tipo de verificação automatizada onde o código de teste interage com a interface gráfica do aplicativo da mesma forma que um usuário real faria. O teste encontra um elemento na tela — um botão, campo de texto, lista — realiza uma ação sobre ele e verifica a resposta esperada da interface. Por exemplo, após inserir uma senha incorreta, um teste de UI verifica se uma mensagem de erro com o texto correto aparece na tela.
A principal diferença entre os testes de UI e outros tipos de automação é que eles funcionam através da camada de acessibilidade do sistema operacional, não através das APIs internas do aplicativo. Isso significa que os testes de UI veem a interface exatamente como um usuário e um leitor de tela a veriam. Graças a isso, os testes de UI verificam não apenas a funcionalidade, mas também a acessibilidade dos elementos — conformidade com os requisitos WCAG.
De acordo com a pesquisa JetBrains Developer Ecosystem 2023, 58% das equipes móveis usam testes de UI em seu pipeline de CI/CD. A cobertura média de testes de UI em projetos comerciais é de 30–40% das telas do aplicativo. Projetos com testes de UI recebem 25% menos avaliações negativas nas lojas de aplicativos relacionadas a falhas de interface.
A principal diferença entre testes de UI e testes unitários é o nível de abstração. Testes unitários trabalham com classes e funções individuais, isoladas do framework Android ou iOS. Eles são executados na JVM (para Android) sem iniciar um emulador e levam milissegundos. Testes de UI são executados em um dispositivo real ou emulador, interagem com serviços do sistema e levam segundos ou minutos por cenário.
O público-alvo dos testes também difere. Testes de UI verificam cenários completos de usuário — registro, realização de pedidos, busca. Testes unitários cobrem a lógica de negócios: cálculos, validação, transformação de dados. Um teste de UI não verifica a corretude do cálculo de imposto — ele verifica se o valor total é exibido na tela. O cálculo em si é verificado por um teste unitário.
De acordo com o Google Testing Blog (2020), a proporção ideal de testes em um projeto segue a regra da pirâmide de testes: 70% de testes unitários, 20% de integração e 10% de UI. A violação dessa proporção em favor dos testes de UI leva ao aumento do tempo de execução e à fragilidade do conjunto de testes, já que os testes de UI são sensíveis a mudanças no layout das telas.
Para Android, o framework dominante é o Espresso — uma biblioteca do Google incorporada ao AndroidX Test. O Espresso sincroniza automaticamente com a thread de UI, aguardando a conclusão de animações e tarefas em segundo plano antes de executar a próxima verificação. Para Jetpack Compose, é usada a extensão Compose UI Test, que funciona através de nós semânticos em vez dos identificadores de visualização tradicionais.
Para iOS, a ferramenta principal é o XCUITest, que faz parte do Xcode. Os testes são escritos em Swift e usam identificadores de acessibilidade para encontrar elementos. O XCUITest suporta gravação de testes através da função de gravação e integração com sistemas CI via xcodebuild. Para projetos multiplataforma, é usado o Appium, baseado no protocolo WebDriver e que permite executar os mesmos testes no Android e iOS com alterações mínimas de código.
Espresso funciona com o sistema tradicional de Views através de onView e identificadores de recursos. O Compose UI Test usa uma camada semântica, tornando os testes menos dependentes da hierarquia de views. Por exemplo, encontrar um botão no Espresso: onView(withId(R.id.submit)), no Compose: onNodeWithTag(“submit”). Os testes do Compose lidam automaticamente com a recomposição e não exigem esperas explícitas de estado ocioso.
XCUITest usa XCUIApplication como ponto de entrada. Cada elemento da interface é encontrado através de propriedades de acessibilidade: accessibilityIdentifier para acesso programático e accessibilityLabel para VoiceOver. O framework suporta gravação de testes através da função de gravação do Xcode — o desenvolvedor realiza ações no simulador e o Xcode gera o código de teste. Os testes prontos são executados via xcodebuild test.
Appium é baseado no protocolo WebDriver e suporta qualquer linguagem: Java, Python, JavaScript. As estratégias de busca de elementos incluem id, xpath, class name e accessibility id. O Appium requer instalação do servidor e configuração das Desired Capabilities — platformName, deviceName, appPackage. Uma alternativa é o Maestro, que usa cenários YAML e não requer compilação de código de teste.
Vamos examinar testes de UI para o mesmo cenário — login no aplicativo — em três frameworks diferentes: Espresso para Android, XCUITest para iOS e Appium para a abordagem multiplataforma. Cenário: inserir login e senha, pressionar o botão de login, verificar a exibição da mensagem de boas-vindas.
Um teste no Espresso usa onView para encontrar um elemento pelo seu identificador e perform para executar uma ação. O método check com o matcher isDisplayed confirma que o elemento está visível na tela.
@RunWith(AndroidJUnit4::class)
class LoginUiTest {
@Rule
@JvmField
val composeTestRule = createComposeRule()
@Test
fun login_withValidCredentials_showsWelcome() {
composeTestRule
.onNodeWithTag("emailField")
.performTextInput("user@example.com")
composeTestRule
.onNodeWithTag("passwordField")
.performTextInput("secret123")
composeTestRule
.onNodeWithTag("loginButton")
.performClick()
composeTestRule
.onNodeWithText("Bem-vindo, Usuário!")
.assertIsDisplayed()
}
}
XCUITest usa XCUIApplication para acessar elementos da interface através de identificadores de acessibilidade. Os métodos tap() e exists fornecem interação e verificação.
class LoginUITests: XCTestCase {
let app = XCUIApplication()
override func setUp() {
continueAfterFailure = false
app.launch()
}
func testLogin_withValidCredentials_showsWelcome() {
app.textFields["emailField"].tap()
app.textFields["emailField"].typeText("user@example.com")
app.secureTextFields["passwordField"].tap()
app.secureTextFields["passwordField"].typeText("secret123")
app.buttons["loginButton"].tap()
XCTAssertTrue(app.staticTexts["Welcome, User!"].exists)
}
}
O primeiro princípio — use identificadores de acessibilidade em vez de rótulos de texto para encontrar elementos. O texto de um botão pode mudar durante a localização, enquanto o identificador permanece estável. No Android, esta é a propriedade contentDescription; no iOS — accessibilityIdentifier. Esta abordagem torna os testes independentes do idioma da interface e reduz custos de manutenção ao alterar o copywriting.
Evite sleep() e atrasos fixos — use os mecanismos de espera integrados do framework. O Espresso aguarda automaticamente a conclusão de animações e tarefas em segundo plano. O XCUITest fornece XCTAssertTrue com timeout. Pausas explícitas tornam os testes mais lentos e instáveis, especialmente em dispositivos lentos em ambiente CI.
Agrupe testes por criticidade: testes smoke (3–5 cenários principais) são executados em cada commit, o conjunto completo de testes de UI é executado antes do lançamento. De acordo com o Google Testing Blog (2022), testes de UI que levam mais de 30 minutos no CI reduzem a frequência de execução em 40%, diminuindo sua eficácia como ferramenta de detecção precoce de regressões.
Os testes de UI têm várias limitações. Sensibilidade a mudanças de layout: alterar um identificador, hierarquia ou tipo de elemento quebra o teste mesmo com funcionalidade inalterada. A solução é usar o padrão Page Object, que centraliza os seletores de elementos em classes separadas. Quando o layout muda, apenas um arquivo Page Object é corrigido, não dezenas de testes.
Tempo de execução: a execução em um dispositivo real ou emulador leva de 10 a 50 vezes mais tempo que um teste unitário. A solução é executar testes de UI em paralelo em vários dispositivos através do Firebase Test Lab ou AWS Device Farm. Instabilidade (flakiness) é um problema comum em execuções CI, causado por animações, atrasos de rede ou estado do emulador. Para combater a instabilidade, são usadas repetições automáticas de testes com falha e análise de estabilidade de cada cenário de teste.
Perguntas frequentes
Para uma tela média, 3–5 testes de UI são suficientes: happy path, validação de erros, estado vazio, mudança de orientação e verificação de acessibilidade. Telas complexas com múltiplos estados — formulários de pedido, configurações — podem exigir 10–15 testes para cobertura completa dos cenários principais.
Sim, Appium e Maestro permitem executar os mesmos cenários em ambas as plataformas. No entanto, os frameworks nativos — Espresso e XCUITest — oferecem melhor estabilidade, velocidade e acesso a recursos específicos da plataforma que não estão disponíveis através de proxies WebDriver.
Para Compose, é usada a biblioteca Compose UI Test com correspondentes semânticos: onNodeWithText, onNodeWithTag, onNodeWithContentDescription. A camada semântica do Compose abstrai a hierarquia de views, tornando os testes menos frágeis em comparação com o Espresso tradicional para o sistema de Views.
A execução básica de testes de UI é feita em emuladores no CI — é rápido e barato. A verificação final antes do lançamento deve ser feita em dispositivos físicos através do Firebase Test Lab para considerar as características do hardware real: diferentes resoluções, versões do SO e desempenho.
Use execução paralela em vários dispositivos, desative animações no emulador através das Opções do Desenvolvedor, construa uma arquitetura de testes modular e execute o conjunto smoke em cada commit, com a execução de regressão completa agendada ou antes do lançamento.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também