Как управлять установками в Appium через noReset и fullReset

Как управлять установками в Appium через noReset и fullReset

🔥 Важное для QA-специалистов! 🔥
В QaRocks ты найдешь туториалы, задачи и полезные книги, которых нет в открытом доступе. Уже более 16.000 подписчиков – будь среди нас! Заходи к нам в телеграм канал QaRocks

Перевод статьи «How to Control Appium Installation with noReset and fullReset».

Мне казалось, что Appium выполняет установку приложений автоматически. Задаем путь к приложению, запускаем драйвер – все, готово.
Но потом меня осенило: я совершенно не знаю, когда мое приложение устанавливается, сбрасывает данные или сохраняет состояние с предыдущих запусков.

Эта проблема проявилась тогда, когда нам нужно было протестировать сборки релиз-кандидатов.

Путь к программе был жестко задан, поэтому для тестирования другой сборки нужно было бы менять код, коммитить и повторно его развертывать. Но наша команда проводила по 20+ тестов в день для разных сборок, и такое промедление было недопустимым.

Проблема оказалась еще глубже: я не понимал, что Appium делал с установкой. Каждый раз переустанавливал приложение? Сохранял приложение между сеансами? Очищал данные? Я опирался на первоначальные настройки, которых не понимал.

Что на самом деле делает Appium при установке

Для управления установкой приложений Appium предлагает две возможности: noReset и fullReset.

Названия непонятные, да и документация ясности не внесет.

noReset: false (по умолчанию)

  • Устанавливает приложение (если оно еще не установлено на устройстве)
  • Сохраняет данные приложения между сеансами драйвера
  • Быстрый, но наследуется состояние с предыдущего сеанса

noReset: true

  • Никогда не трогает установку приложений
  • Предполагает, что приложение уже установлено
  • Самый быстрый вариант. Но уйдет в ошибку, если приложение не установлено

fullReset: false (по умолчанию)

  • Не удаляет приложение между сеансами
  • Сохраняет данные приложения
  • Быстрый, но сохраняется состояние

fullReset: true

  • Полностью удаляет приложение
  • Переустанавливает с нуля
  • Очищает все данные; полный цикл удаления/переустановки на облачных устройствах занимает 30–60 секунд

Как взаимодействуют эти возможности

Обе опции можно сочетать нетривиальным образом. Вот, что происходит:

noResetfullResetЧто происходит
FALSE (по умолчанию)FALSE (по умолчанию)Устанавливает приложение (если оно отсутствует); сохраняет данные между сеансами
FALSETRUEУдаляет -> Переустанавливает -> Сбрасывает данные (избыточно, медленно)
TRUEFALSEПредполагает, что приложение уже установлено; сохраняет данные (быстрый, но рисковый)
TRUETRUEКонфликтный: побеждает noReset, а fullReset игнорируется

Добавляем явное поведение при установке

Работа с дефолтными настройками Appium – это здорово, но вы теряете видимость.

Когда приложение установилось? Когда оно сбросилось? Вы ждете, что Appium сделает все правильно, но сами не знаете, в чем заключается это «правильно».

Добавим следующий флаг, чтобы сделать поведение при установке явным:

private  static  boolean  installedAppPreviously  =  false ; 
if (!installedAppPreviously) { 
capabilities.setCapability( "noReset" , false ); 
capabilities.setCapability( "fullReset" , false ); 
installedAppPreviously = true ; 
}

При создании первого драйвера мы явно задаем обе опции. Тогда приложение установится (при необходимости) и никуда не удалится.

Затем, при последующих созданиях драйверов (если сеанс отрубится), мы больше не прописываем обе эти возможности. Мы опять предоставляем путь к приложению, но Appium распознает, что это приложение уже установлено, и не переустанавливает его.

Установка или управление состоянием

Возможности Appium для управления установкой определяют, что нужно сделать с приложением: установить, переустановить или оставить установленным (не удалять). Но ни одна из них не управляет состоянием приложения между тестами.

Мы обрабатываем это отдельно с перезапуском приложения в хуках @Before. Каждый тест закрывает и снова открывает приложение, очищая память и возвращаясь в исходное состояние.

Важно понять: установка и управление состоянием – это отдельные задачи. Установка делается один раз для каждого набора. Очистка состояния выполняется перед каждым тестом.

Большинство команд помещают очистку в хуки @After. Но если тест A падает, и приложение остается в нарушенном состоянии, то очистка в @After также может завершиться сбоем. Тогда тест B унаследует это несправное состояние и завершится с ложной ошибкой.

Эту проблему решает очистка в @Before. Тест B всегда начинается «с нуля», вне зависимости от того, как завершился тест A. При сбое в очистке тест В не будет 30 секунд отрабатывать логику и выдавать element not found, а завершится сразу с явной ошибкой setup failed.

Дилемма: скорость или исходное состояние

Перезапуск приложения между тестами гарантирует «чистое» (исходное) состояние, но увеличивает непроизводительные затраты. То есть, если по 5 секунд на тест… то для 50 тестов – это уже 4 минуты. На лицо дилемма: исходное состояние или скорость? Но вам важно и то, и другое.

Мы заложили непроизводительные затраты на перезапуск, а все остальное оптимизировали: перешли на стабильные нативные локаторы, очистку перевели в @Before, проработали стратегии ретраев.

В совокупности это сократило время выполнения набора с 2+ часов до ~1,5 часов. 4-минутные затраты на перезапуск стали пренебрежимо малыми.

Динамическое переключение сборок

Вторая проблема: тестирование разных сборок.

Жестко закодированный путь приложения приводит к тому, что нужно влезать в код при каждом тестировании новой сборки.

Решение: переопределять директорию приложения и имя через переменные окружения.

String appDirectory = System.getenv("APP_DIRECTORY");
String appName = System.getenv("APP_NAME");
if (appName != null && !appName.isEmpty()) {
  if (appDirectory == null || appDirectory.isEmpty()) {
    throw new IllegalArgumentException("APP_NAME requires APP_DIRECTORY");
  }
  android_app = appDirectory + "/" + appName + ".apk";
  iOS_app = appDirectory + "/" + appName + ".ipa";
} else {
  android_app = "app-develop.apk";
  iOS_app = "app-develop.ipa";
}

Теперь можно протестировать любую сборку, не меняя код:

# Тестируем дефолтную сборку
mvn test

# Тестируем релиз-кандидата 1.29.0
APP_DIRECTORY="builds/rc" APP_NAME="1.29.0" mvn test

# Тестируем функциональную ветку
APP_DIRECTORY="builds/feature" APP_NAME="new-login" mvn test

Переменная окружения переопределяет значения по умолчанию.

А ваш CI-инструмент умеет передавать эти переменные из UI, так что QA сможет протестировать любую сборку без знания Java.

Настоящая победа

Предсказуемость.

Раньше я не мог точно сказать, когда приложение устанавливалось, и в каком состоянии пребывало.
Сейчас:

  • Приложение устанавливается однократно при запуске тестового набора (noReset: false, fullReset: false)
  • При последующих пересозданиях драйвера шаг с установкой пропускается (флаг installedAppPreviously)
  • Приложение перезапускается между тестами – возврат к исходному состоянию (отдельно от установки)
  • Выбор сборки происходит через переменные окружения (без изменений кода)

Если тест сбоит, я точно знаю, в каком состоянии он запускался. Я могу последовательно воспроизвести сбой и протестировать различные сборки без повторного развертывания кода.

Возможности для установки в Appium не совсем понятны. Стандартные настройки отработают в простых случаях, но сломаются, если вы захотите управлять процессом. Явное поведение (через комбинацию noReset, fullReset и флаги) превращает танцы с бубном во вполне понятную, предсказуемую и отлаживаемую логику.

🔥 Какой была ваша первая зарплата в QA и как вы искали первую работу? 

Мега обсуждение в нашем телеграм-канале о поиске первой работы. Обмен опытом и мнения.

Читать в телеграм

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *