Хабрахабр

[Перевод] Заряжаем суперсилой Appium тесты на Android

Привет, Хабр!

Я работаю в лондонском офисе Badoo в команде Mobile QA Automation. Меня зовут Николай Абалов. Ниже перевод его статьи. Мой коллега Раждип Варма рассказал о том, как сделать Appium-тесты быстрее и надёжнее.

Однако наряду с преимуществами у него есть некоторые ограничения, в частности связанные с тем, что тестовый код полностью отделяется от кода приложения. В последние годы Appium стал одним из самых популярных инструментов автоматизации в мобильной разработке. В этой статье Раждип рассказывает, как вы можете наделить свой код суперсилой и решить самые неприятные проблемы автоматизации end-to-end-тестов для Android.

Проблема №1: капризное приложение


Представьте, что при прогоне теста у вас в приложении возникает какое-то всплывающее сообщение (как на картинке слева). Что, если логика, управляющая отображением сообщения, неподвластна тестировщику? Как в этом случае обеспечить надёжность тестов? Или, скажем, вы хотите кликнуть по двигающемуся баннеру в вашем приложении, но тест проваливается, потому что позиция баннера изменилась к тому моменту, как Appium смог кликнуть!

Есть множество примеров непредсказуемости поведения приложения в ходе тестирования, приводящей к сбоям тестов.

А представьте, что ваши тесты могут сказать приложению: «Я сейчас тебя тестирую, так что отключи, пожалуйста, всплывающее сообщение с просьбой поставить приложению оценку».

Проблема №2: Appium поддерживает не всё

В нашем приложении есть фича, позволяющая, встряхнув устройство, отменить свой отказ от оценки.

Есть конечная точка Shake ((POST /session/:session_id/appium/device/shake), но она не реализована для драйвера UIAutomator2. Как автоматизировать с помощью Appium тряску на Android-устройстве?

А представьте, что ваши тесты могут сказать приложению: «Притворись, что устройство встряхнули».

Решение: позвольте приложению помочь вашим тестам, реализовав бэкдоры

Бэкдоры — способ вызова методов, определённых в коде Android-приложения, из кодовой базы автоматизации, т. е. из ваших тестов.
Давайте рассмотрим это на простом примере. Допустим, у вас есть метод foo()
в Activity, скажем, в классе LoginActivity:

В методе foo() мы можем написать код, отключающий случайные всплывающие сообщения, ИЛИ добавить фальшивую функциональность встряхивания ИЛИ что-то, задающее состояние вашего приложения. Представьте, что мы можем вызывать этот метод из кодовой базы автоматизации с помощью чего-то подобного:

Это решит нашу задачу «А представьте, что ваши тесты могут сказать приложению...»

Плохая новость: бэкдоры не поддерживаются в Appium «из коробки».
Хорошая новость: бэкдоры всё-таки можно реализовать в Appium!

Прежде чем переходить к решению, приведу несколько реальных примеров использования бэкдоров в автоматизации:

  • изменение URL бекенда;
  • изменение географического региона приложения;
  • выбор конкретных вариантов клиентских A/B-тестов;
  • симуляция наличия SIM-карты для приложения;
  • получение ID текущей сессии;
  • получение от приложения данных аналитики.

S. P. Если вас не интересует, как я это сделал, то можете сразу переходить к главе «Быстрое начало работы с бэкдорами в вашем проекте». Делать всё это самостоятельно может быть сложно.

Реализация бэкдоров в Appium


Архитектура «из коробки» сервера UIAutomator2

  1. APK-1 => appium-uiautomator2-server-debug-androidTest.apk
  2. APK-2 => appium-uiautomator2-server.apk

В нём есть тест — instrumentation test. APK-1 — это пакет инструментации (instrumentation package) для APK-2. Его запускает команда для драйвера «adb shell am instrument…» Единственная цель такого теста — запустить HTTP-сервер, определённый в APK-2.

Оба APK-файла выполняются в одном процессе, выделенном на иллюстрации зелёным цветом.

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

Но мы можем выжать максимум из Android-инструментации, если изменим архитектуру (как показано ниже).

Модифицированная архитектура сервера UIAutomator2:


Оснащение тестируемого приложения APK Appium

Следовательно, инструментальный тест и HTTP-сервер теперь находятся в одном APK-файле. Мы влили код APK-2 в APK-1. Назовём его Merged Server APK.

Теперь можно изменить Manifest.xml нашего нового APK-файла таким образом, чтобы его целевым инструментируемым пакетом стал пакет с названием нашего тестируемого приложения:

Это легко реализовать с помощью Ruby Gem под названием appium_instrumenter, в основе которого лежит код из calabash-android gem.

Теперь у нас есть кастомный инструментальный сервер, исполняющийся в том же процессе, что и тестируемое приложение (выделен зелёным цветом). Затем подписываем Merged Server APK с помощью того хранилища ключей (keystore), что и тестируемое приложение.

Это означает, что мы можем попросить файл Merged Server APK вызвать методы, определённые в нашем приложении. Мы инструментировали наше приложение с помощью Merged Server APK, а значит, последний может получить доступ к контексту приложения.

Создадим в Merged Server APK конечную точку, чтобы указывать, какой метод приложения нужно вызвать:

/wd/hub/session/:sessionId/backdoor.

Merged Server APK получает контекст приложения и вызывает метод с помощью API Java Reflection. В эту конечную точку мы можем отправить имя метода, который хотим вызвать.

Весь код этого объединённого с конечной точкой для бэкдоров Appium UIAutomator2 Server вы можете скачать из репозитория, из ветки ‘single_apk’.

Всё самое сложное позади, эти манипуляции нужно проделать только один раз. Далее заменяем APK-файл, поставляемый с пакетом appium_uiautomator2_driver, на наш кастомный APK-файл.

Вот пример на Ruby: Теперь в нашем коде автоматизации тестирования есть вспомогательный метод для вызова бэкдор-методов.

Мы получили суперсилу! Вуаля! Теперь можно очень просто вызвать любой публичный метод, определённый в классе Application или текущем классе Activity:

При этом поддерживается получение тестовым кодом возвращаемых значений!

Быстрое начало работы с бэкдорами в вашем проекте

1. Генерируем APK-файл Appium UIAutomator Server для вашего
приложения:

Даже если ваши Appium-тесты написаны на Java, вам придётся один раз сделать это, поскольку я написал утилиту только на Ruby. установите appium_instrumenter gem.

gem install appium_instrumenter
appium_instrumenter instrument app-debug.apk

В вашей текущей директории создастся папка ./test_servers:

test_servers
├── appium-uiautomator2-server-debug-androidTest.apk
└── appium-uiautomator2-server-v0.3.0.apk

Установите на устройство оба вышеупомянутых APK-файла:

adb install test_servers/appium-uiautomator2-server-debug-androidTest.apk
adb install test_servers/appium-uiautomator2-server-v0.3.0.apk

2. Теперь установите NPM-пакет appium_uiautomator2_driver из моего форка:

npm install “rajdeepv/appium-uiautomator2-driver#adb_host”

3. Определите метод backdoor():

определите метод, отправляющий данные в конечную точку для бэкдора:

http://localhost:#/wd/hub/session/:sessionId/backdoor

Вы можете реализовать такой же метод, если пишете на Java или любом другом языке. Рассмотрите приведённый выше пример реализации этого метода на Ruby.

4. Да прибудет с вами суперсила!

Держитесь от проблем подальше

«С большой силой приходит и большая ответственность».

И при неправильном использовании он может привести к неприятным последствиям. Бэкдор — очень мощный инструмент. Так, если мы воспользуемся бэкдором для полного изменения логики приложения, то риски тестирования будут выше, чем его ценность.

И в некоторых случаях без них просто не обойтись! Бэкдоры позволяют реализовать ранее невозможные сценарии, они расширяют возможности тестирования.

К слову, 1 апреля Раждип выступил на CodeFest в Новосибирске. Вот такая история. Видеозапись его доклада должна появиться летом на YouTube-канале CodeFest и на Badoo Tech.

Теги
Показать больше

Похожие статьи

Добавить комментарий

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

Кнопка «Наверх»
Закрыть