TL;DR
- Appium автоматизирует iOS и Android приложения через WebDriver протокол — один фреймворк, обе платформы
- Настройка: Appium сервер, SDK платформ (Android Studio/Xcode), клиентская библиотека
- Поиск элементов по accessibility id, xpath или платформенным локаторам
- Поддержка жестов (свайп, скролл, тап), реальных устройств и эмуляторов/симуляторов
- Интеграция с CI/CD через Appium в Docker или облачные сервисы (BrowserStack, Sauce Labs)
Идеально для: QA-команд, тестирующих мобильные приложения на разных платформах Пропусти, если: Тестируешь только Android (используй Espresso) или только iOS (используй XCUITest) Время чтения: 20 минут
Твоё приложение работает на iOS. Падает на Android. Или наоборот. Ручное тестирование на обеих платформах удваивает усилия. Паритет функций становится кошмаром.
Appium решает кросс-платформенное мобильное тестирование. Пишешь один тест, запускаешь на iOS и Android. Один язык, один фреймворк, один CI-пайплайн.
Этот туториал покрывает Appium от настройки до CI/CD интеграции — всё, что нужно для автоматизации мобильных приложений.
Что такое Appium?
Appium — это open-source фреймворк для мобильной автоматизации. Он автоматизирует нативные, гибридные и мобильные веб-приложения на iOS и Android через протокол WebDriver.
Как работает Appium:
- Твой тестовый код отправляет команды на Appium сервер
- Appium переводит команды в платформенные действия
- UIAutomator2 (Android) или XCUITest (iOS) выполняет действия
- Результаты возвращаются по той же цепочке
Почему Appium:
- Кросс-платформенность — одни тесты для iOS и Android
- Независимость от языка — Java, Python, JavaScript, Ruby, C#
- Без модификации приложения — тестирует реальные продакшен-билды
- Стандарт WebDriver — знакомый API для пользователей Selenium
- Open-source — бесплатный, активное сообщество, регулярные обновления
Настройка окружения
Предварительные требования
Для Android:
- Java JDK 11+
- Android Studio с SDK
- Переменная окружения
ANDROID_HOME - USB-отладка включена на устройстве
Для iOS (только macOS):
- Xcode с Command Line Tools
- iOS Симулятор или реальное устройство
- Аккаунт Apple Developer (для реальных устройств)
Установка Appium
# Установка Appium 2.x глобально
npm install -g appium
# Проверка установки
appium --version
# Установка драйверов платформ
appium driver install uiautomator2 # Android
appium driver install xcuitest # iOS
# Список установленных драйверов
appium driver list --installed
Appium Inspector
Установи Appium Inspector для инспекции элементов:
- Скачай с GitHub releases
- Или используй веб-версию на inspector.appiumpro.com
Desired Capabilities
Capabilities сообщают Appium, какое устройство и приложение использовать.
Android Capabilities
from appium import webdriver
from appium.options.android import UiAutomator2Options
options = UiAutomator2Options()
options.platform_name = "Android"
options.device_name = "Pixel 6"
options.app = "/path/to/app.apk"
options.automation_name = "UiAutomator2"
# Опционально, но рекомендуется
options.no_reset = True # Не сбрасывать состояние приложения
options.full_reset = False
options.new_command_timeout = 300
driver = webdriver.Remote("http://localhost:4723", options=options)
iOS Capabilities
from appium import webdriver
from appium.options.ios import XCUITestOptions
options = XCUITestOptions()
options.platform_name = "iOS"
options.device_name = "iPhone 14"
options.platform_version = "16.0"
options.app = "/path/to/app.app"
options.automation_name = "XCUITest"
# Для реальных устройств
options.udid = "device-udid-here"
driver = webdriver.Remote("http://localhost:4723", options=options)
Тестирование установленных приложений
# Android - используй package и activity
options.app_package = "com.example.myapp"
options.app_activity = "com.example.myapp.MainActivity"
# iOS - используй bundle ID
options.bundle_id = "com.example.myapp"
Поиск элементов
Стратегии локаторов
from appium.webdriver.common.appiumby import AppiumBy
# Accessibility ID (рекомендуется - работает кросс-платформенно)
element = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_button")
# ID (Android resource-id)
element = driver.find_element(AppiumBy.ID, "com.example:id/login_button")
# XPath (медленнее, но гибко)
element = driver.find_element(AppiumBy.XPATH, "//android.widget.Button[@text='Login']")
# Class name
element = driver.find_element(AppiumBy.CLASS_NAME, "android.widget.EditText")
# Android UIAutomator
element = driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiSelector().text("Login")'
)
# iOS predicate string
element = driver.find_element(
AppiumBy.IOS_PREDICATE,
'label == "Login" AND type == "XCUIElementTypeButton"'
)
# iOS class chain
element = driver.find_element(
AppiumBy.IOS_CLASS_CHAIN,
'**/XCUIElementTypeButton[`label == "Login"`]'
)
Ожидание элементов
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, 10)
# Ожидание видимости элемента
element = wait.until(
EC.visibility_of_element_located((AppiumBy.ACCESSIBILITY_ID, "welcome_message"))
)
# Ожидание кликабельности
element = wait.until(
EC.element_to_be_clickable((AppiumBy.ACCESSIBILITY_ID, "submit_button"))
)
# Ожидание исчезновения элемента
wait.until(
EC.invisibility_of_element_located((AppiumBy.ACCESSIBILITY_ID, "loading_spinner"))
)
Базовые взаимодействия
Тап, ввод текста, очистка
# Тап/Клик
login_button = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_button")
login_button.click()
# Ввод текста
username_field = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "username")
username_field.send_keys("testuser")
# Очистка поля
username_field.clear()
# Получение текста
message = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "message")
print(message.text)
# Проверка отображения/активности
assert login_button.is_displayed()
assert login_button.is_enabled()
Работа с клавиатурой
# Скрыть клавиатуру
driver.hide_keyboard()
# Проверить, показана ли клавиатура (Android)
is_keyboard_shown = driver.is_keyboard_shown()
Жесты
Свайп и скролл
from appium.webdriver.common.touch_action import TouchAction
# Простой свайп (start_x, start_y, end_x, end_y, duration_ms)
driver.swipe(500, 1500, 500, 500, 800)
# Скролл к элементу (Android)
driver.find_element(
AppiumBy.ANDROID_UIAUTOMATOR,
'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().text("Target Text"))'
)
# Скролл по направлению
def scroll_down(driver):
size = driver.get_window_size()
start_x = size['width'] // 2
start_y = size['height'] * 0.8
end_y = size['height'] * 0.2
driver.swipe(start_x, start_y, start_x, end_y, 500)
def scroll_up(driver):
size = driver.get_window_size()
start_x = size['width'] // 2
start_y = size['height'] * 0.2
end_y = size['height'] * 0.8
driver.swipe(start_x, start_y, start_x, end_y, 500)
W3C Actions (рекомендуется)
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.actions import interaction
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.common.actions.pointer_input import PointerInput
# Тап по координатам
actions = ActionChains(driver)
actions.w3c_actions = ActionBuilder(driver, mouse=PointerInput(interaction.POINTER_TOUCH, "touch"))
actions.w3c_actions.pointer_action.move_to_location(100, 200)
actions.w3c_actions.pointer_action.pointer_down()
actions.w3c_actions.pointer_action.pause(0.1)
actions.w3c_actions.pointer_action.release()
actions.perform()
# Долгое нажатие
element = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "item")
actions = ActionChains(driver)
actions.click_and_hold(element).pause(2).release().perform()
Полный пример теста
import pytest
from appium import webdriver
from appium.options.android import UiAutomator2Options
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class TestLoginFlow:
@pytest.fixture(autouse=True)
def setup(self):
options = UiAutomator2Options()
options.platform_name = "Android"
options.device_name = "emulator-5554"
options.app = "./app-debug.apk"
options.automation_name = "UiAutomator2"
options.no_reset = False
self.driver = webdriver.Remote("http://localhost:4723", options=options)
self.wait = WebDriverWait(self.driver, 15)
yield
self.driver.quit()
def test_successful_login(self):
# Ввод имени пользователя
username = self.wait.until(
EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "username_input"))
)
username.send_keys("testuser@example.com")
# Ввод пароля
password = self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, "password_input")
password.send_keys("securepassword123")
# Скрыть клавиатуру
self.driver.hide_keyboard()
# Нажать кнопку входа
login_btn = self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_button")
login_btn.click()
# Проверить приветствие
welcome = self.wait.until(
EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "welcome_message"))
)
assert "Welcome" in welcome.text
def test_invalid_credentials(self):
username = self.wait.until(
EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "username_input"))
)
username.send_keys("wrong@example.com")
password = self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, "password_input")
password.send_keys("wrongpassword")
self.driver.hide_keyboard()
login_btn = self.driver.find_element(AppiumBy.ACCESSIBILITY_ID, "login_button")
login_btn.click()
# Проверить сообщение об ошибке
error = self.wait.until(
EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "error_message"))
)
assert "Invalid credentials" in error.text
Паттерн Page Object
# pages/base_page.py
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
class BasePage:
def __init__(self, driver):
self.driver = driver
self.wait = WebDriverWait(driver, 15)
def find(self, locator):
return self.wait.until(EC.presence_of_element_located(locator))
def click(self, locator):
self.find(locator).click()
def type_text(self, locator, text):
element = self.find(locator)
element.clear()
element.send_keys(text)
# pages/login_page.py
class LoginPage(BasePage):
USERNAME = (AppiumBy.ACCESSIBILITY_ID, "username_input")
PASSWORD = (AppiumBy.ACCESSIBILITY_ID, "password_input")
LOGIN_BTN = (AppiumBy.ACCESSIBILITY_ID, "login_button")
ERROR_MSG = (AppiumBy.ACCESSIBILITY_ID, "error_message")
def login(self, username, password):
self.type_text(self.USERNAME, username)
self.type_text(self.PASSWORD, password)
self.driver.hide_keyboard()
self.click(self.LOGIN_BTN)
def get_error_message(self):
return self.find(self.ERROR_MSG).text
# tests/test_login.py
class TestLogin:
def test_login_success(self, driver):
login_page = LoginPage(driver)
login_page.login("user@example.com", "password123")
# assertions...
Тестирование на реальных устройствах
Android реальное устройство
# Подключить устройство по USB
adb devices
# Получить имя устройства
adb shell getprop ro.product.model
# Включить USB-отладку в настройках разработчика
options.device_name = "Pixel 6"
options.udid = "emulator-5554" # или реальный серийный номер
iOS реальное устройство
Требуется provisioning profile и подпись:
options.udid = "00008030-001234567890"
options.xcode_org_id = "TEAM_ID"
options.xcode_signing_id = "iPhone Developer"
Облачные фермы устройств
BrowserStack:
from appium import webdriver
options = {
"platformName": "Android",
"appium:deviceName": "Samsung Galaxy S23",
"appium:platformVersion": "13.0",
"appium:app": "bs://app-id",
"bstack:options": {
"userName": "YOUR_USERNAME",
"accessKey": "YOUR_ACCESS_KEY",
"projectName": "My Project",
"buildName": "Build 1.0"
}
}
driver = webdriver.Remote(
"https://hub-cloud.browserstack.com/wd/hub",
options=options
)
Интеграция с CI/CD
GitHub Actions
name: Mobile Tests
on: [push, pull_request]
jobs:
android-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: |
pip install appium-python-client pytest
npm install -g appium
appium driver install uiautomator2
- name: Start Android emulator
uses: reactivecircus/android-emulator-runner@v2
with:
api-level: 33
script: |
appium &
sleep 10
pytest tests/android/ --junitxml=results.xml
- name: Upload results
uses: actions/upload-artifact@v4
with:
name: test-results
path: results.xml
Appium с помощью ИИ
ИИ-инструменты могут помочь писать и отлаживать Appium-тесты.
Что ИИ делает хорошо:
- Генерация page objects из скриншотов приложения
- Предложение стратегий локаторов
- Отладка ошибок поиска элементов
- Конвертация тестов между языками
Что всё ещё требует людей:
- Понимание бизнес-логики приложения
- Выбор между нестабильными и стабильными локаторами
- Оптимизация времени выполнения тестов
- Обработка платформенных edge cases
FAQ
Что такое Appium?
Appium — это open-source фреймворк для мобильной автоматизации тестирования iOS и Android приложений. Он использует протокол WebDriver, позволяя писать тесты на любом языке с WebDriver-клиентом (Java, Python, JavaScript, Ruby, C#). Appium может тестировать нативные, гибридные и мобильные веб-приложения без модификации — тестируешь реальные продакшен-билды.
Appium бесплатный?
Да, Appium полностью бесплатен и open-source под лицензией Apache 2.0. Нет enterprise-версий, премиум-функций или лимитов использования. Весь фреймворк, включая все драйверы (UiAutomator2, XCUITest), доступен бесплатно.
Appium или Espresso/XCUITest — что лучше?
Appium отлично подходит для кросс-платформенного тестирования — пишешь тесты один раз, запускаешь на iOS и Android. Espresso (Android) и XCUITest (iOS) платформенно-специфичны, но быстрее, стабильнее и имеют глубокую интеграцию с ОС. Используй Appium, когда нужно кросс-платформенное покрытие одним кодом. Используй нативные инструменты, когда нужна максимальная скорость и надёжность для одной платформы.
Может ли Appium тестировать и iOS, и Android?
Да, это главное преимущество Appium. Один и тот же тестовый код может работать на обеих платформах с минимальными изменениями — обычно только разные локаторы для платформенных элементов. Пишешь тесты на предпочитаемом языке, а Appium переводит команды в соответствующую платформенную автоматизацию (UiAutomator2 для Android, XCUITest для iOS).
Официальные ресурсы
Смотрите также
- API Testing Guide - Полное руководство по API-тестированию
- Selenium Tutorial - Основы веб-автоматизации
- Playwright Tutorial - Современный фреймворк для веб-тестирования
- CI/CD Testing Guide - Стратегии непрерывной интеграции
