Что такое Appium?

Appium — это фреймворк мобильной автоматизации с открытым исходным кодом, позволяющий писать тесты для приложений Android и iOS с использованием стандартного протокола WebDriver. Ключевая философия Appium — не нужно перекомпилировать или модифицировать приложение для его автоматизации, и можно писать тесты на любом языке программирования.

Appium работает как сервер, принимающий команды WebDriver от тестового кода и транслирующий их в платформо-специфичные действия автоматизации. Для Android он использует UIAutomator2 или Espresso как базовый движок. Для iOS — XCUITest. Этот уровень абстракции делает Appium кроссплатформенным — тестовый код вызывает один и тот же API WebDriver независимо от целевой платформы.

Архитектура Appium

Тестовый скрипт (Java/Python/JS/C#)
         |
    Клиент WebDriver
         |
    HTTP (протокол W3C WebDriver)
         |
    Сервер Appium (Node.js)
         |
    +---------+---------+
    |                   |
  Android             iOS
  (UIAutomator2)     (XCUITest)
    |                   |
  Устройство/        Устройство/
  Эмулятор           Симулятор

Ключевые компоненты

Сервер Appium: Node.js-приложение, принимающее команды WebDriver по HTTP, транслирующее их в платформо-специфичные команды и возвращающее результаты. Управляет сессиями, подключениями устройств и драйверами автоматизации.

Драйверы Appium: Платформо-специфичные модули, знающие как автоматизировать каждую платформу. Драйвер UiAutomator2 управляет Android; драйвер XCUITest управляет iOS. Каждый драйвер понимает фреймворк доступности и иерархию UI платформы.

Клиентские библиотеки: Стандартные клиентские библиотеки WebDriver (привязки Selenium) с расширениями Appium. Доступны для Java, Python, JavaScript, C#, Ruby и других языков.

Appium Inspector: GUI-инструмент для инспекции дерева элементов мобильного приложения, тестирования локаторов и записи действий. Необходим для построения селекторов элементов.

Настройка Appium

Предварительные требования

Для Android:

  • Java JDK 11+
  • Android SDK с platform tools
  • Эмулятор Android или физическое устройство с включённой отладкой по USB
  • Установленная переменная окружения ANDROID_HOME

Для iOS (только macOS):

  • Xcode с инструментами командной строки
  • Симулятор iOS или физическое устройство с действующим профилем подготовки

Установка

# Установить Appium 2.x глобально
npm install -g appium

# Установить драйверы
appium driver install uiautomator2   # Для Android
appium driver install xcuitest       # Для iOS

# Запустить сервер
appium

# Установить Appium Inspector (отдельная загрузка)
# https://github.com/appium/appium-inspector/releases

Проверка настройки

# Проверить окружение
npx appium-doctor --android   # Проверить настройку Android
npx appium-doctor --ios       # Проверить настройку iOS

W3C Capabilities

Capabilities сообщают Appium, какое устройство, платформу и приложение использовать:

// Пример на 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
);
// Пример на 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
);

Поиск элементов

Appium Inspector

Appium Inspector подключается к работающей сессии и отображает дерево элементов приложения. Можно:

  • Просматривать иерархию UI
  • Кликать по элементам для просмотра атрибутов
  • Тестировать стратегии локации в реальном времени
  • Копировать код локаторов на предпочтительном языке

Стратегии локации

// По Accessibility ID (рекомендуется — кроссплатформенный)
driver.findElement(AppiumBy.accessibilityId("loginButton"));

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

// По XPath (медленный, но гибкий)
driver.findElement(AppiumBy.xpath("//android.widget.Button[@text='Login']"));

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

// По Android UIAutomator селектору (только Android, мощный)
driver.findElement(AppiumBy.androidUIAutomator(
    "new UiSelector().text(\"Login\")"
));

// По iOS predicate string (только iOS)
driver.findElement(AppiumBy.iOSNsPredicateString(
    "label == 'Login' AND type == 'XCUIElementTypeButton'"
));

Лучшая практика: Используйте Accessibility ID по возможности. Работает на обеих платформах и является самой надёжной стратегией локации.

Типичные мобильные действия

Нажатие, ввод и свайп

// Нажатие на элемент
WebElement loginBtn = driver.findElement(AppiumBy.accessibilityId("loginButton"));
loginBtn.click();

// Ввод текста
WebElement emailField = driver.findElement(AppiumBy.accessibilityId("emailInput"));
emailField.sendKeys("user@example.com");

// Очистить и ввести заново
emailField.clear();
emailField.sendKeys("new@example.com");

// Скрыть клавиатуру (Android)
driver.hideKeyboard();

Жесты с W3C Actions

// Свайп вверх (скролл вниз)
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));

Паттерн Page Object для мобильных

// 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();
    }
}

// Тестовый класс
@Test
public void testSuccessfulLogin() {
    LoginPage loginPage = new LoginPage(driver);
    DashboardPage dashboard = loginPage.loginAs("admin@test.com", "password123");
    assertEquals("Welcome, Admin", dashboard.getWelcomeText());
}

Тесты на реальных устройствах vs эмуляторах

АспектЭмулятор/СимуляторРеальное устройство
СкоростьБыстрый запуск, медленнее выполнениеМедленнее настройка, реалистичная скорость
СтоимостьБесплатноПокупка устройства или облачный сервис
НадёжностьСтабильный, воспроизводимыйИногда проблемы с подключением
ТочностьМожет пропустить аппаратные багиТестирует реальные условия пользователя
CI/CDЛегко развернутьНужна device farm или облако

Рекомендация: Используйте эмуляторы для ежедневных CI/CD-прогонов и реальные устройства для предрелизной валидации и аппаратных функций (камера, GPS, биометрия).

Упражнения

Упражнение 1: Настройка Appium и первый тест

  1. Установите Appium 2.x и драйвер UiAutomator2
  2. Скачайте пример приложения (например, тестовое приложение Appium)
  3. Откройте Appium Inspector и исследуйте дерево элементов приложения
  4. Напишите тест, который открывает приложение, переходит на определённый экран и проверяет видимость элементов

Упражнение 2: Поток логина с Page Objects

  1. Создайте page objects для потока логина: LoginPage, DashboardPage
  2. Напишите тесты для: успешный логин, неверный пароль, пустые поля
  3. Используйте локаторы Accessibility ID для всех элементов
  4. Добавьте явные ожидания для состояний загрузки

Упражнение 3: Автоматизация жестов

  1. Напишите тест, который скроллит список для поиска конкретного элемента
  2. Реализуйте действие long-press, вызывающее контекстное меню
  3. Создайте тест pinch-to-zoom для просмотра изображения
  4. Протестируйте жест swipe-to-delete на элементе списка