Testes Mobile: Guia Completo para Apps iOS e Android

Testes Automatizados · 6 de julho de 2026

📖 7 min de leitura

Introdução aos Testes Mobile

Testar aplicativos mobile apresenta desafios únicos: múltiplas versões de OS, diferentes tamanhos de tela, conectividade variável e interação touch. Uma estratégia de teste mobile eficaz deve cobrir dispositivos, plataformas e condições de uso diversas.

Panorama Mobile

Dado Valor
Apps disponíveis 6.5+ milhões
Tempo médio em apps 4.8 horas/dia
Usuários mobile 7.33 bilhões
Fragmentação Android 24.000+ dispositivos
iOS versions ativas 4-5 simultâneas

Estratégia de Testes Mobile

Pirâmide de Testes Mobile

              /
             /           E2E Tests
            /____        (10{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442})
           /             Funcionalidade completa
          /              em dispositivos reais
         /__________
        /               Integration Tests
       /______________  (20{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442})
      /                 Componentes e módulos
     /__________________
    /                     Unit Tests
   /______________________ (70{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442})
   Componentes e lógica

Dispositivos: Emuladores vs. Reais

Aspecto Emuladores Dispositivos Reais
Custo Grátis Dispositivos físicos
Velocidade Mais lentos Mais rápidos
Acurácia Limitada Real
Hardware CPU/RAM limitados Real performance
Sensores Simulados Reais (GPS, câmera)
Rede Controlável Real, variável

Recomendação: Usar ambos – emuladores para CI/rapidez, dispositivos reais para QA final.


Ferramentas de Teste Mobile

1. Appium – Cross-Platform

Melhor para: Testes cross-platform (iOS + Android) com uma codebase.

Instalação

# macOS com Homebrew
brew install node
npm install -g appium
npm install -g appium-doctor
appium &

Configuração Android

# SDK Android
export ANDROID_HOME=~/Android/Sdk
export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools

# Start emulador
$ANDROID_HOME/emulator/emulator -avd Pixel_6_API_33

Script Appium (Python)

from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy
from appium.webdriver.common.touch_action import TouchAction
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class TestApp:
@pytest.fixture
def driver(self):
capabilities = {
"platformName": "Android",
"deviceName": "Pixel_6_API_33",
"app": "/path/to/app.apk",
"automationName": "UiAutomator2",
"autoGrantPermissions": True
}

driver = webdriver.Remote(
"http://localhost:4723/wd/hub",
capabilities
)
yield driver
driver.quit()

def test_login_flow(self, driver):
# Aguardar elementos
wait = WebDriverWait(driver, 10)

# Clicar no campo email
email_field = wait.until(
EC.presence_of_element_located(
(AppiumBy.ANDROID_UIAUTOMATOR, 'resourceId("com.app:id/email")')
)
)
email_field.send_keys("usuario@test.com")

# Clicar no campo senha
driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR,
'resourceId("com.app:id/password")'
).send_keys("senha123")

# Clicar em Login
driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR,
'text("Entrar")'
).click()

# Verificar redirecionamento para dashboard
wait.until(
EC.presence_of_element_located(
(AppiumBy.ANDROID_UIAUTOMATOR, 'text("Dashboard")')
)
)

def test_swipe_gesture(self, driver):
# Obter tamanho da tela
size = driver.get_window_size()
start_x = size['width'] * 0.5
start_y = size['height'] * 0.8
end_y = size['height'] * 0.2

# Swipe up
TouchAction(driver).press(start_x, start_y).move_to(0, -500).release().perform()

def test_scroll_to_element(self, driver):
# Scroll até encontrar elemento
driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiScrollable(new UiSelector()).scrollIntoView(text("Settings"))'
)

2. Espresso – Android Nativo

Melhor para: Projetos Android com Kotlin/Java.

Dependências (build.gradle)

androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test:rules:1.5.0'

Script Espresso (Kotlin)

package com.example.app

import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import static androidx.test.espresso.Espresso.*
import static androidx.test.espresso.action.ViewActions.*
import static androidx.test.espresso.assertion.ViewAssertions.*
import static androidx.test.espresso.matcher.ViewMatchers.*

@RunWith(AndroidJUnit4::class)
@LargeTest
class LoginTest {

@get:Rule
val activityRule = ActivityScenarioRule(LoginActivity::class.java)

@Test
fun testLoginWithValidCredentials() {
// Preencher email
onView(withId(R.id.email_input))
.perform(typeText("usuario@test.com"), closeSoftKeyboard())

// Preencher senha
onView(withId(R.id.password_input))
.perform(typeText("senha123"), closeSoftKeyboard())

// Clicar em Login
onView(withId(R.id.login_button))
.perform(click())

// Verificar navegação para Dashboard
onView(withId(R.id.dashboard_title))
.check(matches(isDisplayed()))
}

@Test
fun testLoginWithInvalidCredentials() {
onView(withId(R.id.email_input))
.perform(typeText("invalido@test.com"))
.perform(typeText("senhaerrada"), closeSoftKeyboard())

onView(withId(R.id.login_button)).perform(click())

// Verificar mensagem de erro
onView(withId(R.id.error_message))
.check(matches(withText("Credenciais inválidas")))
}

@Test
fun testScrollThroughList() {
// Scroll down
onView(withId(R.id.product_list))
.perform(
RecyclerViewActions.scrollTo(
hasDescendant(withText("Product 50"))
)
)

// Clicar no item
onView(withText("Product 50"))
.perform(click())
}
}

3. XCTest – iOS Nativo

Melhor para: Projetos iOS com Swift/Objective-C.

Script XCTest (Swift)

import XCTest

class LoginTests: XCTestCase {

var app: XCUIApplication!

override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments = ["--uitesting"]
app.launch()
}

func testLoginWithValidCredentials() {
// Acessar campos
let emailField = app.textFields["email_input"]
let passwordField = app.secureTextFields["password_input"]
let loginButton = app.buttons["login_button"]

// Preencher credenciais
emailField.tap()
emailField.typeText("usuario@test.com")

passwordField.tap()
passwordField.typeText("senha123")

// Clicar em Login
loginButton.tap()

// Verificar Dashboard
XCTAssertTrue(
app.staticTexts["dashboard_title"].waitForExistence(timeout: 5)
)
}

func testPullToRefresh() {
// Encontrar UITableView
let tableView = app.tables["product_list"]

// Pull to refresh
let firstCell = tableView.cells.element(boundBy: 0)
let cellCenter = firstCell.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
let pullPoint = cellCenter.withOffset(CGVector(dx: 0, dy: -100))

cellCenter.press(forDuration: 0, thenDragTo: pullPoint)

// Verificar refresh indicator
XCTAssertTrue(app.activityIndicators["refresh_indicator"].exists)
}

func testSwipeToDelete() {
let tableView = app.tables["product_list"]
let cell = tableView.cells.element(boundBy: 0)

// Swipe left
cell.swipeLeft()

// Clicar em Delete
app.buttons["delete_button"].tap()

// Verificar confirmação
app.alerts["Confirma exclusão?"].buttons["Excluir"].tap()
}
}


Testes em Dispositivos Reais

Serviços de Cloud Testing

Serviço Dispositivos Preço Melhor Para
BrowserStack 3000+ $29+/mês Cobertura completa
Sauce Labs 1000+ $39+/mês Enterprise
AWS Device Farm 数百 Sob demanda AWS integration
Firebase Test Lab 数百 Pay-per-use Android focused

Setup BrowserStack

# pytest + BrowserStack
from appium import webdriver

def get_browserstack_driver():
desired_caps = {
"platformName": "android",
"deviceName": "Samsung Galaxy S23",
"os_version": "13.0",
"app": "bs://APP_ID",
"browserstack.user": "USER",
"browserstack.key": "ACCESS_KEY",
"browserstack.debug": True,
"browserstack.networkLogs": True
}

return webdriver.Remote(
"http://hub-cloud.browserstack.com/wd/hub",
desired_caps
)


Cenários de Teste Mobile

1. Testes de Interface

def test_responsividade_telas():
    """Testa layouts em diferentes tamanhos de tela"""
    sizes = [
        (360, 640),  # Small phone
        (390, 844),  # iPhone 12/13
        (412, 915),  # Large phone
        (600, 1024), # Tablet portrait
    ]

for width, height in sizes:
driver.execute_script(f"setWindowSize({width}, {height})")

# Verificar elementos não se sobrepõem
assert not elements_overlap(header, footer)
assert text_is_readable(header)

2. Testes de Conectividade

def test_offline_mode():
    """Testa comportamento sem internet"""
    # Desligar rede
    driver.set_network_connection(0)  # Airplane mode

# Tentar acessar conteúdo offline
assert app.has_cached_content()
assert app.can_show_cached_products()

# Tentar ação que requer internet
with pytest.raises(NetworkError):
app.submit_order()

# Reconectar
driver.set_network_connection(6) # WiFi

# Sincronizar
app.sync_pending_orders()
assert order.was_synced()

3. Testes de Performance

@Test
fun testListScrollPerformance() {
    val recyclerView = espresso.onView(
        withId(R.id.product_list)
    )

// Medir FPS durante scroll
val monitor = FrameMetricsMonitor()

recyclerView.perform(
scrollToPosition(100),
scrollToPosition(50),
scrollToPosition(0)
)

val metrics = monitor.getMetrics()

// Verificar 60 FPS (16.67ms por frame)
assertThat(metrics.averageFrameTime).isLessThan(20.0)
assertThat(metrics.droppedFrames).isLessThan(5)
}


Appium + CI/CD

GitHub Actions

name: Mobile Tests

on: [push, pull_request]

jobs:
android-tests:
runs-on: macos-latest

steps:
- uses: actions/checkout@v4

- name: Setup Java
uses: actions/setup-java@v4
with:
java-version: '17'

- name: Setup Android SDK
uses: android-actions/setup-android@v2

- name: Cache Appium
uses: actions/cache@v3
with:
path: node_modules
key: ${{ runner.os }}-appium

- name: Install Dependencies
run: |
npm ci
pip install pytest pytest-appium

- name: Run Tests on BrowserStack
env:
BROWSERSTACK_USER: ${{ secrets.BS_USER }}
BROWSERSTACK_KEY: ${{ secrets.BS_KEY }}
run: |
pytest tests/mobile/
--device="Samsung Galaxy S23"
--platform="Android 13"
--hub="http://hub.browserstack.com/wd/hub"


Conclusão

Testes mobile requerem estratégia bem definida cobrindo múltiplas plataformas, dispositivos e condições. As chaves para sucesso são:

  1. Automação estratégica – Appium para cross-platform, nativo para performance
  2. Device matrix – Priorizar por uso real
  3. CI/CD integrado – Testes em cloud para escalabilidade
  4. Performance monitorada – FPS, memória, bateria
  5. Testes de condições reais – Offline, network switching


FAQ

P: Appium é mais lento que Espresso/XCTest?
R: Sim, mas permite código único para iOS e Android.

P: Quantos dispositivos testar?
R: Foque nos top 10-20 dispositivos por mercado (iOS, Android).

P: Como testar notificações push?
R: Use emuladores para automação, dispositivos reais para validação final.

P: Testes mobile podem ser 100{6727d158e4474b0847515bd23a8ee4bebd5f1aac7a18bc968e51d8985dccb442} automatizados?
R: Não. Alguns testes (usabilidade, exploratory) requerem testers humanos.