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:
- Automação estratégica – Appium para cross-platform, nativo para performance
- Device matrix – Priorizar por uso real
- CI/CD integrado – Testes em cloud para escalabilidade
- Performance monitorada – FPS, memória, bateria
- 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.
