Que Es Appium?

Appium es un framework de automatizacion movil de codigo abierto que te permite escribir tests para aplicaciones Android e iOS usando el protocolo estandar WebDriver. La filosofia clave detras de Appium es que no deberias necesitar recompilar tu app o modificarla de ninguna manera para automatizarla, y deberias poder escribir tests en cualquier lenguaje de programacion.

Appium actua como un servidor que recibe comandos WebDriver de tu codigo de test y los traduce en acciones de automatizacion especificas de la plataforma. Para Android, usa UIAutomator2 o Espresso como motor de automatizacion subyacente. Para iOS, usa XCUITest. Esta capa de abstraccion es lo que hace a Appium multiplataforma — tu codigo de test llama la misma API WebDriver sin importar la plataforma objetivo.

Arquitectura de Appium

Script de Test (Java/Python/JS/C#)
         |
    Cliente WebDriver
         |
    HTTP (Protocolo W3C WebDriver)
         |
    Servidor Appium (Node.js)
         |
    +---------+---------+
    |                   |
  Android             iOS
  (UIAutomator2)     (XCUITest)
    |                   |
  Dispositivo/       Dispositivo/
  Emulador           Simulador

Componentes Clave

Servidor Appium: Una aplicacion Node.js que recibe comandos WebDriver via HTTP, los traduce en comandos especificos de plataforma y devuelve resultados. Gestiona sesiones, conexiones de dispositivos y drivers de automatizacion.

Drivers de Appium: Modulos especificos de plataforma que saben como automatizar cada una. El driver UiAutomator2 controla Android; el driver XCUITest controla iOS. Cada driver comprende el framework de accesibilidad y la jerarquia de UI de la plataforma.

Bibliotecas Cliente: Bibliotecas cliente WebDriver estandar (bindings de Selenium) con extensiones especificas de Appium. Disponibles para Java, Python, JavaScript, C#, Ruby y mas.

Appium Inspector: Una herramienta GUI para inspeccionar el arbol de elementos de la app movil, probar locators y grabar acciones. Esencial para construir selectores de elementos.

Configurando Appium

Prerrequisitos

Para Android:

  • Java JDK 11+
  • Android SDK con platform tools
  • Un emulador Android o dispositivo fisico con depuracion USB habilitada
  • Variable de entorno ANDROID_HOME configurada

Para iOS (solo macOS):

  • Xcode con herramientas de linea de comandos
  • Un simulador iOS o dispositivo fisico con perfil de aprovisionamiento valido

Instalacion

# Instalar Appium 2.x globalmente
npm install -g appium

# Instalar drivers
appium driver install uiautomator2   # Para Android
appium driver install xcuitest       # Para iOS

# Iniciar el servidor
appium

# Instalar Appium Inspector (descarga separada)
# https://github.com/appium/appium-inspector/releases

Verificar Configuracion

# Verificar entorno
npx appium-doctor --android   # Verificar setup de Android
npx appium-doctor --ios       # Verificar setup de iOS

W3C Capabilities

Las capabilities le dicen a Appium que dispositivo, plataforma y app usar:

// Ejemplo Java — Android
UiAutomator2Options options = new UiAutomator2Options()
    .setPlatformName("Android")
    .setDeviceName("Pixel_7_API_34")
    .setApp("/path/to/app.apk")
    .setAutomationName("UiAutomator2")
    .setAppPackage("com.example.myapp")
    .setAppActivity("com.example.myapp.MainActivity")
    .setNoReset(true);

AndroidDriver driver = new AndroidDriver(
    new URL("http://localhost:4723"), options
);
// Ejemplo Java — iOS
XCUITestOptions options = new XCUITestOptions()
    .setPlatformName("iOS")
    .setDeviceName("iPhone 15")
    .setPlatformVersion("17.0")
    .setApp("/path/to/app.ipa")
    .setAutomationName("XCUITest")
    .setBundleId("com.example.myapp");

IOSDriver driver = new IOSDriver(
    new URL("http://localhost:4723"), options
);

Encontrando Elementos

Appium Inspector

Appium Inspector se conecta a una sesion en ejecucion y muestra el arbol de elementos de la app. Puedes:

  • Navegar la jerarquia de UI
  • Hacer click en elementos para ver sus atributos
  • Probar estrategias de localizacion en tiempo real
  • Copiar codigo de localizacion en tu lenguaje preferido

Estrategias de Localizacion

// Por Accessibility ID (recomendado — multiplataforma)
driver.findElement(AppiumBy.accessibilityId("loginButton"));

// Por ID (Android resource ID)
driver.findElement(AppiumBy.id("com.example:id/login_button"));

// Por XPath (lento pero flexible)
driver.findElement(AppiumBy.xpath("//android.widget.Button[@text='Login']"));

// Por Class Name
driver.findElement(AppiumBy.className("android.widget.EditText"));

// Por selector Android UIAutomator (solo Android, poderoso)
driver.findElement(AppiumBy.androidUIAutomator(
    "new UiSelector().text(\"Login\")"
));

// Por iOS predicate string (solo iOS)
driver.findElement(AppiumBy.iOSNsPredicateString(
    "label == 'Login' AND type == 'XCUIElementTypeButton'"
));

Mejor practica: Usa Accessibility ID siempre que sea posible. Funciona en ambas plataformas y es la estrategia de localizacion mas confiable.

Acciones Moviles Comunes

Tap, Escritura y Swipe

// Tap en un elemento
WebElement loginBtn = driver.findElement(AppiumBy.accessibilityId("loginButton"));
loginBtn.click();

// Escribir texto
WebElement emailField = driver.findElement(AppiumBy.accessibilityId("emailInput"));
emailField.sendKeys("user@example.com");

// Limpiar y reescribir
emailField.clear();
emailField.sendKeys("new@example.com");

// Ocultar teclado (Android)
driver.hideKeyboard();

Gestos con W3C Actions

// Swipe arriba (scroll abajo)
Dimension size = driver.manage().window().getSize();
int startX = size.width / 2;
int startY = (int) (size.height * 0.8);
int endY = (int) (size.height * 0.2);

PointerInput finger = new PointerInput(PointerInput.Kind.TOUCH, "finger");
Sequence swipe = new Sequence(finger, 1);
swipe.addAction(finger.createPointerMove(Duration.ZERO, PointerInput.Origin.viewport(), startX, startY));
swipe.addAction(finger.createPointerDown(PointerInput.MouseButton.LEFT.asArg()));
swipe.addAction(finger.createPointerMove(Duration.ofMillis(500), PointerInput.Origin.viewport(), startX, endY));
swipe.addAction(finger.createPointerUp(PointerInput.MouseButton.LEFT.asArg()));
driver.perform(List.of(swipe));

Patron Page Object para Movil

// BasePage.java
public abstract class BasePage {
    protected AndroidDriver driver;
    protected WebDriverWait wait;

    public BasePage(AndroidDriver driver) {
        this.driver = driver;
        this.wait = new WebDriverWait(driver, Duration.ofSeconds(10));
    }

    protected WebElement waitForElement(By locator) {
        return wait.until(ExpectedConditions.visibilityOfElementLocated(locator));
    }
}

// LoginPage.java
public class LoginPage extends BasePage {
    private final By emailInput = AppiumBy.accessibilityId("emailInput");
    private final By passwordInput = AppiumBy.accessibilityId("passwordInput");
    private final By loginButton = AppiumBy.accessibilityId("loginButton");
    private final By errorMessage = AppiumBy.accessibilityId("errorMessage");

    public LoginPage(AndroidDriver driver) {
        super(driver);
    }

    public DashboardPage loginAs(String email, String password) {
        waitForElement(emailInput).sendKeys(email);
        waitForElement(passwordInput).sendKeys(password);
        waitForElement(loginButton).click();
        return new DashboardPage(driver);
    }

    public String getErrorMessage() {
        return waitForElement(errorMessage).getText();
    }
}

// Clase de test
@Test
public void testSuccessfulLogin() {
    LoginPage loginPage = new LoginPage(driver);
    DashboardPage dashboard = loginPage.loginAs("admin@test.com", "password123");
    assertEquals("Welcome, Admin", dashboard.getWelcomeText());
}

Tests en Dispositivos Reales vs Emuladores

AspectoEmulador/SimuladorDispositivo Real
VelocidadRapido para iniciar, ejecucion mas lentaMas lento para configurar, velocidad realista
CostoGratisCompra de dispositivo o servicio cloud
ConfiabilidadConsistente, reproducibleProblemas ocasionales de conectividad
PrecisionPuede omitir bugs especificos de hardwarePrueba condiciones reales del usuario
CI/CDFacil de provisionarRequiere device farm o cloud

Recomendacion: Usa emuladores para ejecuciones diarias de CI/CD y dispositivos reales para validacion pre-lanzamiento y funcionalidades especificas de hardware (camara, GPS, biometria).

Ejercicios

Ejercicio 1: Configuracion de Appium y Primer Test

  1. Instala Appium 2.x y el driver UiAutomator2
  2. Descarga una app de ejemplo (como la app de test de Appium)
  3. Abre Appium Inspector y explora el arbol de elementos de la app
  4. Escribe un test que abra la app, navegue a una pantalla especifica y verifique visibilidad de elementos

Ejercicio 2: Flujo de Login con Page Objects

  1. Crea page objects para un flujo de login: LoginPage, DashboardPage
  2. Escribe tests para: login exitoso, password invalido, campos vacios
  3. Usa locators de Accessibility ID para todos los elementos
  4. Agrega esperas explicitas para estados de carga

Ejercicio 3: Automatizacion de Gestos

  1. Escribe un test que haga scroll a traves de una lista para encontrar un item especifico
  2. Implementa una accion de long-press que active un menu contextual
  3. Crea un test de pinch-to-zoom para una vista de imagen
  4. Testea un gesto de swipe-to-delete en un item de lista