Что такое 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 и первый тест
- Установите Appium 2.x и драйвер UiAutomator2
- Скачайте пример приложения (например, тестовое приложение Appium)
- Откройте Appium Inspector и исследуйте дерево элементов приложения
- Напишите тест, который открывает приложение, переходит на определённый экран и проверяет видимость элементов
Упражнение 2: Поток логина с Page Objects
- Создайте page objects для потока логина: LoginPage, DashboardPage
- Напишите тесты для: успешный логин, неверный пароль, пустые поля
- Используйте локаторы Accessibility ID для всех элементов
- Добавьте явные ожидания для состояний загрузки
Упражнение 3: Автоматизация жестов
- Напишите тест, который скроллит список для поиска конкретного элемента
- Реализуйте действие long-press, вызывающее контекстное меню
- Создайте тест pinch-to-zoom для просмотра изображения
- Протестируйте жест swipe-to-delete на элементе списка