Pull to refresh

Автоматизация тестирования мобильного приложения КриптоАРМ Mobile на Android

Level of difficultyMedium
Reading time24 min
Views491

В этой статье мы проведем обзор современных инструментов и подходов для тестирования мобильных приложений на примере приложения КриптоАРМ Mobile под Android. Подробно расскажем о настройке окружения для создания тестов, а также разработаем Docker-контейнер, который обеспечит удобный запуск тестов. Кроме того, мы рассмотрим процесс автоматизации тестирования и его интеграцию в CI/CD, что позволит упростить и ускорить процесс разработки и тестирования приложений.

Предисловие

Примерно год назад компания столкнулась с необходимостью перехода от ручного тестирования приложений к внедрению автоматизации этого процесса. После исследования инструментов, которые могут помочь с решением этой задачи, выводы оказались неутешительными. Бесплатных инструментов для тестирования мобильных приложений не так уж и много и выбирать особо не из чего. Так как в компании уже была практика тестирования web-сервисов с использованием Selenium WebDriver, выбор был сделан в пользу Appium и его окружения.

Обзор инструментов для тестирования мобильных приложений : современное состояние

Наличие современного инструментария для тестирования имеет важное значение и существенно влияет на производительность выпуска мобильных приложений. Как и подавляющее большинство специалистов данного направления мы начали с мониторинга предложений в сфере программных продуктов для тестирования. 

LambdaTest

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

Страница сервиса тестирования LambdaTest
Страница сервиса тестирования LambdaTest

Это платформа для управления выполнением тестов на основе искусственного интеллекта (ИИ), которая позволяет тестировать свои приложения на симуляторах и эмуляторах и на реальных устройствах. Эмулятор мобильного приложения — виртуальная платформа, которая имитирует устройство Android на рабочем хосте, собственно, что нам и требуется. Симулятор  — виртуальная платформа, которая имитирует операционную систему iOS и запускает приложение на выбранном устройстве Apple (например, симулятор iPhone), без необходимости использования физического устройства. В будущем нам это тоже пригодится.

Основная проблема с этим сервисом заключается в том, что он работает по Freemium модели и владельцы сервиса сразу же хотят денег. Кто знает, какая политика будет через год-два.  

Appium

Вторым решением был рассмотрен фреймворк Appium. Прямо скажем, решение не совсем новое, но поддерживаемое до сих пор. 

Документация по фреймворку Appium
Документация по фреймворку Appium

Appium — инструмент (фреймворк, хотя есть и скомпилированные приложения) для автоматизированного тестирования с открытым исходным кодом. Он может использоваться как для тестирования приложений Android, так и для тестирования iOS. 

Инструмент абсолютно бесплатный, но клиент-серверная модель Appium требует продвинутых навыков для корректной настройки сервера и создания необходимой инфраструктуры для тестирования. Как раз этому вопросу и посвящена статья.

Robotium

Eще одно решение —  Robotium. Проект довольно старый и сейчас не поддерживается, но в свое время был перспективным решением.

Проект Robotium на GitHub
Проект Robotium на GitHub

Также является решением с открытым исходным кодом. Как заявляли разработчики, основной фишкой фреймворка является возможность обработки нескольких действий в приложении Android. Под действиями понимаются разные экраны или разделы приложения. И там присутствует Robotium Recorder, что так недостает в Appium. Из-за чего создание тестов очень сильно растянуто по времени, хотя чек-листы уже составлены. Но у разработчиков продукта что-то пошло не так, и он благополучно канул. 

Selenoid

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

Интерфейс Selenoid с несколькими активными сеансами
Интерфейс Selenoid с несколькими активными сеансами

Как раз в нем тесты пишутся с использованием API клиента Selenium 2, известного как Selenium WebDriver.  Дополнительных преимуществ этого решения по масштабированию и параллельному тестированию нескольких приложений нам не требуется, поэтому его применение осталось под вопросом. Хотя Selenium WebDriver подключается и задействуется во фреймворке Appium.

После нескольких дней поиска и чтения документации различных проектов и сервисов мы все-таки остановили свой выбор на Appium. На данный момент это решение без альтернатив.

Настраиваем окружение для создания тестов мобильного приложения КриптоАРМ Mobile под Android

Для разработки тестов мобильного приложения КриптоАРМ Mobile решили использовать набор инструментария под платформу Windows. Выбор платформы не принципиален, так как все инструменты можно установить и под Linux, но с точки зрения правки и заполнения check-листов работа становится более комфортной. Сам дистрибутив приложения мы получаем от разработчиков в виде готового APK, который после сборки заливается на FTP-server, например, https://ftp.digt.ru/web/PublicReleases/CryptoARM_Mobile/v1.0.30/cryptoarm-1.0.30.apk

 То программное окружение, которое нам необходимо установить и настроить состоит из:

  • Android Studio (дистрибутив можно скачать отсюда. На сайте среды разработки https://developer.android.com/studio в разделе Download также размещены дистрибутивы под Mac и Linux).

  • Appium Server (приложение можно скачать здесь. Есть образы для Linux и Mac).

  • Appium Inspector (приложение можно скачать здесь. Есть также сборки под Linux и Mac, и даже плагин для интеграции инспектора в сервер Appium).

  • Intellij PyCharm (IDE для разработки на Python, была скачана и установлена версия PyCharm Community Edition отсюда).

Теперь разберемся для чего нам каждый компонент и в каком порядке будем их устанавливать и настраивать. Android Studio — среда для разработки приложений под Android, здесь нам понадобится эмулятор системы и больше ничего (напомню, что приложения к нам попадают уже в собранном виде, например, cryptoarm-1.0.30.apk и выполнять его сборку нам не нужно. Из данного пакета мы будем задействовать менеджер виртуальных устройств и эмулятор. При желании их можно попытаться установить отдельно и сэкономить ресурсы, но мы решили пойти по простому пути.

Appium Server — это собственно сервер, который реализован в виде приложения на Electron c GUI интерфейсом. В репозитории, где размещено приложение следует обратить внимание на надпись, что данное приложение уже не поддерживается (последняя версия была выпущена в 2022 году) и содержит уязвимости. К тому же по заявлению разработчиков, приложение содержит уязвимости. Крамольная идея запустить его на сервере и начать работу может обернуться большими проблемами, поэтому мы используем его локально для разработки тестов не увеличивая риски. 

Appium Inspector — это приложение с GUI интерфейсом, предназначенное для просмотра элементов (компонент) приложения. В процессе создания тестов нам понадобятся пути к различным элементам и их состояния (либо какие-то другие свойства), все это в визуальном представлении можно считать в инспекторе. Собственно в самом тестировании он не участвует и нужен только на этапе создания тестов.

Intellij PyCharm — это полноценная IDE для работы с проектами на Python. В качестве библиотеки тестирования мы выбрали PyTest, хотя Appium поддерживает создание тестов на массе других языков. Использование среды разработки PyCharm дает определенный комфорт при разработке массивных проектов тестов. Среда тоже нам нужна только на этапе создания тестов, в процессе прогона готовый нам понадобится только python (плюс необходимые библиотеки pytest) и сами тесты. 

Ну что же, начнем установку и настройку программных компонент нашей инфраструктуры для разработки тестов. Сначала устанавливаем Android Studio, среда включает в себя Android SDK. Обязательно необходимо проверить, что SDK с нужной версией Android Studio установлен, а сделать это можно при запуске Android Studio через SDK Manager.

Переход через меню к установке SDK
Переход через меню к установке SDK

После выбора SDK Manager появится окно настроек, в котором мы выбираем необходимую версию платформы Android (они не установлены изначально и будут выкачиваться отдельно. При скачивании можно обращать внимание на пути, они понадобятся при настройке серверной части).  

Выбор требуемого SDK Android для установки
Выбор требуемого SDK Android для установки

Как только мы установили платформу, возвращаемся к списку системных переменных и добавляем переменную ANDROID_HOME со значением каталога, в котором у нас установлен SDK, а так же обновляем переменную Path, добавляя значение %ANDROID_HOME%\bin. Под Windows это делается так.

Добавление необходимых путей
Добавление необходимых путей

Затем можно приступать к установке и настройке  Appium Server. Это сервер, который будет связывать наши написанные тестовые скрипты с мобильным приложением с помощью запросов REST API. По умолчанию сервер работает по локальному адресу 127.0.0.1 через порт 4723. 

Интерфейс приложения Appium Server
Интерфейс приложения Appium Server

Через кнопку Изменить конфигурации можно проверить настройки окружения, которые определяются через системные переменные. 

Необходимые настройки для запуска сервера
Необходимые настройки для запуска сервера

По кнопке Запуск сервера запускаем сервер.

Запуск сервера и первые логи
Запуск сервера и первые логи

Далее нам нужно определиться, на каком устройстве будет выполняться тест – реальном или виртуальном. Тестировать на реальном устройстве мы пока не будем, а виртуальное устройство можно создать в Android Studio через AVD Manager, взяв параметры реального устройства или же создать свое индивидуальное. Снова идем в Android Studio и в выпадающем списке More Actions находим Virtual Device Manager. Если никаких устройств нет, то увидим следующее окно

Создание виртуального устройства с ОС Android
Создание виртуального устройства с ОС Android

После создания, в списке будут присутствовать виртуальные устройства

Список созданных виртуальных устройств
Список созданных виртуальных устройств

Пока далеко не ушли от этого компонента. Есть важное примечание. В дополнительном меню, напротив каждого из виртуальных устройств есть пункт Cold Boot. Мы его используем в том случае, если в процессе создания тестов приложение зависло на устройстве и подвесило всю систему. Тогда с помощью этого пункта меню можно сделать рестарт устройства и устранить данную проблему. 

В том случае, когда для тестов необходимо использовать реальное устройство, то его можно подключить с помощью USB к компьютеру, с которого мы будем запускать тест и перейти в режим разработчика. Для этого в настройках телефона ищем строку с версией Android и быстро кликаем по ней, пока система не сообщит, что мы перешли в режим разработчика. После этого появится раздел настроек для разработчиков, в котором нужно активировать опции «Установка через USB» и «Отладка через USB».

Дополнительные настройки
Дополнительные настройки

После того, как мы настроили виртуальное устройство, его можно запустить. APK в процессе разработки тестов можно просто перетащить мышкой на область экрана эмулятора и приложения прекрасно устанавливается. Если нужна некоторая степень автоматизации — можно это делать с помощью командной строки, при настройке серверной части мы так и поступим. После запуска эмулятора, установки и запуска приложения мы увидим следующее (на экране мастер нашего приложения)

Запуск нашего приложения на эмуляторе
Запуск нашего приложения на эмуляторе

Теперь нужно установить и настроить Appium Inspector. Это что-то наподобие панели разработчика в браузере, через которую мы определяем селекторы для html-элементов приложения Android. При запуске приложения хост, порт и путь уже выставлены по умолчанию. 

Необходимые настройки Appium Inspector
Необходимые настройки Appium Inspector

Нам нужно правильно указать настройки устройства: "appium:deviceName" – это имя нашего виртуального устройства (это имя, которые мы ввели при создании виртуального устройства в Device Manager), "platformName" – в нашем случае это Android, "automationName" — драйвер с помощью которого обеспечивается связь с виртуальным устройством (так как мы тестирует с виртуальным устройством на Android, то вариантов у нас немного — используем драйвер uiautomator2),  "appPackage" — ключ, который указывает на название пакета приложения, "appActivity" — ключ, который указывает на главную (или стартовую) активность приложения. Эти настройки формируются в виде небольшого JSON и сохраняются для последующего использования. Когда все приготовления пройдены, нажимаем на кнопку Начать сессию. С этого момента все оживает, на экране сервера начинает динамически формировать лог операций, а в эмуляторе приложение закрывается и снова стартует с главного экрана. Представление экрана эмулятора переносится в инспектор, где можно с помощью мыши выбирать элементы управления и просматривать их свойства.

Подключение Appium Inspector к эмулятору (через драйвер uiautomator2)
Подключение Appium Inspector к эмулятору (через драйвер uiautomator2)

Для тестов, обычно, мы используем xpath элементов управления. Теперь осталось установить среду разработки Intellij PyCharm, и можно начинать создание тестов.

Пример создания и запуска тестов для OS Android

Итак, эмулятор приложения у нас запущен, в активном состоянии сервер Appium и инспектор. Устанавливаем Intellij PyCharm, создаем новый проект и первый файл python. Так как приложение может не работать уже изначально при запуске, мы обычно, делаем первый тест на системных компонентах Android. Пример можно взять из документации Appium. В простейшем виде код первого теста (файл system.py) выглядит следующим образом:

import pytest

from appium import webdriver

from appium.webdriver.common.appiumby import AppiumBy

from appium.options.android import UiAutomator2Options

capabilities = dict(

    platformName='Android',

    automationName='uiautomator2',

    deviceName='sdk_gphone_x86_64',

    appPackage='com.android.settings',

    appActivity='.Settings'

)

appium_server_url = 'http://localhost:4723/wd/hub'

@pytest.fixture(scope='module')

def driver():

    capabilities_options = UiAutomator2Options().load_capabilities(capabilities)

    driver = webdriver.Remote(command_executor=appium_server_url, options=capabilities_options)

    yield driver

    driver.quit()

def test_find_battery(driver):

    el = driver.find_element(by=AppiumBy.XPATH, value='//*[@text="Battery"]')

    el.click()

При переносе этого кода в PyCharm, не забудьте установить pytest и appium. Среда разработки делает это в полуавтоматическом режиме. По поводу appium_server_url, здесь указан путь по которому создается сессия с сервером. Так как сервер приложения у нас версии 1.22, этот путь корректен. Но если вы используете Appium версии 2.0 и выше, то путь необходимо изменить и он будет иметь вид appium_server_url = 'http://localhost:4723'.

По настройкам для веб-драйвера все предельно ясно:  platformName — указание платформы, automationName — указание драйвера, deviceName — имя нашего виртуального устройства, appPackage — название пакета приложения (в данном случае мы используем системный компонент), appActivity — активность приложения.

@pytest.fixture(scope='module') —  декоратор, который определяет фикстуру для тестов. Параметр scope='module' указывает, что фикстура будет создана один раз на весь модуль (т.е. для всех тестов в этом файле). Собственно в функции driver() создается экземпляр драйвера с заданными параметрами.

Функция test_find_battery(driver) — определяет тестовую функцию, которая использует фикстуру driver в качестве аргумента. В ней используется драйвер для поиска элемента на экране мобильного приложения. В данном случае элемент ищется по XPath, который соответствует тексту "Battery". После нахождения элемента, происходит клик по нему.

Запускаем данный тест на выполнения и все успешно. Тест пройден.

Запуск первых тестов PyTest
Запуск первых тестов PyTest

C помощью Appium Inspector для интересующих нас экранов приложения выясняем идентификаторы элементов и используем их для составления тестов. Вот фрагмент теста для нашего приложения: 

import pytest

import random

from appium import webdriver

from appium.webdriver.common.appiumby import AppiumBy

from time import sleep

from appium.options.android import UiAutomator2Options

from selenium.webdriver.support.ui import WebDriverWait

from selenium.webdriver.support import expected_conditions as EC

capabilities = dict(

    platformName='Android',

    automationName='uiautomator2',

    deviceName='sdk_gphone_x86_64',

    appPackage='com.cryptoarm',

    appActivity='.MainActivity'

)

appium_server_url = 'http://localhost:4723/wd/hub'

@pytest.fixture(scope='module')

def driver():

    capabilities_options = UiAutomator2Options().load_capabilities(capabilities)

    driver = webdriver.Remote(command_executor=appium_server_url, options=capabilities_options)

    yield driver

    driver.quit()

def test_for_android(driver):

    # Запуск приложения

    driver.activate_app('com.cryptoarm')

    print("Приложение открыто.")

    sleep(10)

    # Пропускаем шаги мастера

    el = WebDriverWait(driver, 10).until(

        EC.element_to_be_clickable((AppiumBy.XPATH, '//android.widget.FrameLayout[@resource-id="android:id/content"]/android.widget.FrameLayout/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup[2]/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup[7]'))

    )

    el.click()

    sleep(5)

    # Переходим к генерации ключей

    el = WebDriverWait(driver, 10).until(

        EC.element_to_be_clickable((AppiumBy.XPATH, '//android.widget.FrameLayout[@resource-id="android:id/content"]/android.widget.FrameLayout/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup[2]/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup/android.view.ViewGroup[6]'))

    )

    el.click()

    sleep(5)

и так далее.

Разработка Docker-контейнера для запуска тестов

Чтобы тесты не требовали ручного запуска каждый раз с выходом нового релиза, важно автоматизировать процесс тестирования. Это можно сделать с помощью систем, которые поддерживают автоматический запуск тестов — например, GitLab. Такие инструменты дают возможность настроить запуск тестов сразу после изменения кода.

Однако перед автоматизацией важно настроить среду, где будут выполняться тесты. Такой средой могут быть различные удаленные серверы, виртуальные машины, эмуляторы или контейнеры, например, Docker. Этот выбор среды зависит от требований и спецификаций проекта. В нашем случае необходимо настроить процесс мобильного тестирования. При автоматизации для данного вида тестирования используют либо готовые эмуляторы, либо использовать уже преднастроенные Docker-образы. 

В качестве программной среды, где будет отлаживаться наш docker-образ можно использовать Docker Desktop (скачиваем здесь) под Windows раз уж мы сидим на этой платформе. Выглядит интерфейс так 

Запуск Docker Desktop под Windows
Запуск Docker Desktop под Windows

как раз раздел Вulds нам и понадобится.

Начнем разработку нашего Docker-образа. Для этого нам нужно создать файл dockerfile и определится на какой платформе мы организуем программное окружение (мы выбрали для тестов ubuntu версии 24.04).  Организуем рабочую директорию, устанавливаем необходимые пакеты и утилиты и ставим jdk (понадобится для запуска эмулятора).

FROM ubuntu:24.04

#=======================

# Рабочая директория

#=======================

WORKDIR /

#=======================

# Основные пакеты

#=======================

RUN apt-get -qqy update && \

    apt-get -qqy --no-install-recommends install \

    mc \

    ca-certificates \

    tzdata \

    zip \

    unzip \

    curl \

    wget \

    libqt5webkit5 \

    xvfb \

    gnupg \

    python3 \

    python3-pip \

    openjdk-17-jdk \  

    qemu-kvm \

    libvirt-daemon-system \

    libvirt-clients \

    bridge-utils \

  && rm -rf /var/lib/apt/lists/*

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

ENV JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64

ENV PATH="${JAVA_HOME}/bin:${PATH}"

Далее по сценарию нам необходимо установить Android SDK, причем не абы какой, а тот который будет использоваться при тестировании — не самый последний, но и не очень старый. В итоге остановились на платформе с API_LEVEL="34". Если захотите изменить платформу все необходимые параметры можно посмотреть в Android Studio для созданного виртуального устройства.

#=========================================

# Аргументы для установки Android SDK

#=========================================

ARG ARCH="x86_64" 

ARG ANDROID_ARCH_DEFAULT="x86_64" 

ARG TARGET="google_apis"  

ARG API_LEVEL="34" 

ARG BUILD_TOOLS="34.0.0"

ARG ANDROID_BUILD_TOOLS_VERSION=34.0.0

ARG ANDROID_ARCH=${ANDROID_ARCH_DEFAULT}

ARG ANDROID_API_LEVEL="android-${API_LEVEL}"

ARG ANDROID_APIS="${TARGET};${ARCH}"

ARG EMULATOR_PACKAGE="system-images;${ANDROID_API_LEVEL};${ANDROID_APIS}"

ARG PLATFORM_VERSION="platforms;${ANDROID_API_LEVEL}"

ARG BUILD_TOOL="build-tools;${BUILD_TOOLS}"

ARG SDK_VERSION=commandlinetools-linux-13114758_latest

ARG ANDROID_SDK_PACKAGES="${EMULATOR_PACKAGE} ${PLATFORM_VERSION} ${BUILD_TOOL} platform-tools emulator"

ENV SDK_VERSION=$SDK_VERSION \

    ANDROID_BUILD_TOOLS_VERSION=$ANDROID_BUILD_TOOLS_VERSION \

    ANDROID_SDK_ROOT=/opt/android

RUN mkdir -p /opt/android-sdk/cmdline-tools && \

    cd /opt/android-sdk/cmdline-tools && \

    wget https://dl.google.com/android/repository/${SDK_VERSION}.zip -O cmdline-tools.zip && \

    unzip cmdline-tools.zip -d latest && \

    rm cmdline-tools.zip && \

    mv latest/cmdline-tools/* latest/ || true && \

    rm -rf latest/cmdline-tools || true

ENV ANDROID_HOME=/opt/android-sdk

ENV ANDROID_AVD_HOME=/data

ENV ADB_DIR="$ANDROID_HOME/platform-tools"

ENV EMULATOR_DIR="$ANDROID_HOME/emulator"

ENV PATH="$ANDROID_HOME/cmdline-tools/latest/bin:$ADB_DIR:$EMULATOR_DIR:$PATH"

RUN mkdir /root/.android/ && \

	touch /root/.android/repositories.cfg && \

	mkdir /data && \

    mkdir /extras

RUN yes | sdkmanager --sdk_root=$ANDROID_HOME "emulator" "platform-tools" "platforms;android-34" "system-images;android-34;google_apis;x86_64"

RUN echo no | avdmanager "--verbose" "create" "avd" "--force" "--name" "emulator" "--device" "pixel_3a" "--package" "system-images;android-34;google_apis;x86_64" "--tag" "google_apis" "--abi" "x86_64" "--sdcard" "512M"

Последним этапом мы устанавливаем node.js, appium server, определяем доступные порты и подгружаем скрипт запуска сервера. 

#==========================================

# Установка nodejs, npm и appium server

#==========================================

RUN curl -sL https://deb.nodesource.com/setup_20.x | bash && \

    apt-get -qqy install nodejs && \

    npm install -g npm && \

    npm i -g appium --unsafe-perm=true --allow-root && \

    appium driver install uiautomator2 && \

    exit 0 && \

    npm cache clean && \

    apt-get remove --purge -y npm && \  

    apt-get autoremove --purge -y && \

    apt-get clean && \

    rm -Rf /tmp/* && rm -Rf /var/lib/apt/lists/*

#=============================

# Порты

#=============================

ENV APPIUM_PORT=4723

#=============================

# Скрипт запуска сервера

#=============================

COPY start-appium.sh /usr/local/bin/start-appium.sh

RUN chmod +x /usr/local/bin/start-appium.sh

CMD ["/usr/local/bin/start-appium.sh"]

С самим dockerfile мы закончили. Осталось заполнить скрипт start-appium.sh.

#!/bin/bash

# Запуск сервера Appium

appium &

emulator_name="emulator"

emulator -avd "emulator" -no-boot-anim -gpu off

function check_hw_support() {

    if [[ "$HW_ACCEL_OVERRIDE" != "" ]]; then

        hw_accel_flag="$HW_ACCEL_OVERRIDE"

    else

        # общая проверка аппаратной акселерации для Linux

        HW_ACCEL_SUPPORT=$(grep -E -c '(vmx|svm)' /proc/cpuinfo)

        if [[ $HW_ACCEL_SUPPORT == 0 ]]; then

            hw_accel_flag="-accel off"

        else

            hw_accel_flag="-accel on"

        fi
Первая часть кода связана с решением проблемы использования аппаратной виртуализации (большинство виртуальных устройств с не очень старым SDK требуют наличия такой возможности и под Linux приходится устанавливать и настраивать kvm. Здесь можно найти неплохую статью как это можно сделать.). Далее мы устанавливаем необходимые пакеты pytest, стартуем виртуальное устройство (создали мы его чуть раньше в dockerfile) и проверяем список запущенных устройств. Затем запускаем Appium Server. Вот и все, пора опробовать.
    fi

    echo "$hw_accel_flag"

}

hw_accel_flag=$(check_hw_support)

function run_emulator () {

  adb devices | grep emulator | cut -f1 | xargs -I {} adb -s "{}" emu kill

  options="@${emulator_name} -no-window -no-snapshot -noaudio -no-boot-anim -memory 2048 ${hw_accel_flag} -camera-back none"

  

  if [[ "$OSTYPE" == linux ]]; then

    echo "${OSTYPE}: эмулятор ${options} -gpu off"

    nohup emulator $options -gpu off &

  fi

  

  if [[ "$OSTYPE" == darwin ]] || [[ "$OSTYPE" == macos ]]; then

    echo "${OSTYPE}: эмулятор ${options} -gpu swiftshader_indirect"

    nohup emulator $options -gpu swiftshader_indirect &

  fi

  if [ $? -ne 0 ]; then

    echo "❌ Ошибка при запуске эмулятора"

    return 1

  fi

}

function check_emulator () {

  echo -e "📦 Проверка статуса загрузки эмулятора \n"

  start_time=$(date +%s)

  i=0

  timeout=${EMULATOR_TIMEOUT:-300}

  while true; do

    result=$(adb shell getprop sys.boot_completed 2>&1)

    if [ "$result" == "1" ]; then

      printf "🔥 Эмулятор готов : '%s'\n" "$result"

      adb devices -l

      adb shell input keyevent 82

      break

    elif [ "$result" == "" ]; then

      printf "⚠️ Эмулятор частично загружен!\n"

    else

      printf "\n%s, пожалуйста, подождите\n" "$result"

      i=$(( (i+1) % 8 ))

    fi

    current_time=$(date +%s)

    elapsed_time=$((current_time - start_time))

    if [ $elapsed_time -gt $timeout ]; then

      printf "Время ожидания истекло через %d секунд 🕛..\n" "$timeout"

      break

    fi

    sleep 4

  done

};

function disable_animation() {

  adb shell "settings put global window_animation_scale 0.0"

  adb shell "settings put global transition_animation_scale 0.0"

  adb shell "settings put global animator_duration_scale 0.0"

};

function hidden_policy() {

  adb shell "settings put global hidden_api_policy_pre_p_apps 1;settings put global hidden_api_policy_p_apps 1;settings put global hidden_api_policy 1"

};

run_emulator

sleep 2

check_emulator

sleep 1

disable_animation

sleep 1

hidden_policy

sleep 1

# Ожидание, чтобы контейнер не завершился

wait

Первая часть кода связана с решением проблемы использования аппаратной виртуализации (большинство виртуальных устройств с не очень старым SDK требуют наличия такой возможности и под Linux приходится устанавливать и настраивать kvm. Здесь можно найти неплохую статью как это можно сделать.). Далее мы устанавливаем необходимые пакеты pytest, стартуем виртуальное устройство (создали мы его чуть раньше в dockerfile) и проверяем список запущенных устройств. Затем запускаем Appium Server. Вот и все, пора опробовать.

Открываем наш Docker Desktop на вкладке Builds, открываем терминал и в текущей директории, где расположен наш dockerfile и скрипт  start-appium.sh стартуем команду (не упустите в конце точку, она тоже относится к команде сборки)

docker build -t registry.example.ru/dt_test/mobile:v2.0.0 .

Эта команда запускает сборку образа относительно инструкций в нашем dockerfile, причем если вы хотите заливать готовый образ в GitLab, то можно указать путь registry.example.ru/dt_test/mobile:v2.0.0, как в нашем случае. Если будете использовать локально, то можно поставить любое имя. Процесс пошел и займет некоторое время.

Сборка нашего образа на основе dockerfile
Сборка нашего образа на основе dockerfile

Если с dockerfile и описанием процесса сборки все нормально, то на вкладке Images мы увидим наш образ и можем сделать запуск контейнера на его основе, чтобы проверить работу. 

Запуск контейнера
Запуск контейнера

Для запуска контейнера нам нужно использовать команду, то есть выставить привилегированный режим, смонтировать kvm и прописать порты:

docker run --privileged --device=/dev/kvm -p 6080:6080 -p 4723:4723 -p 5554:5554 -p 5555:5555 -it registry.example.ru/dt_test/mobile:v2.0.0

Запущенный контейнер с Appium и эмулятором Android
Запущенный контейнер с Appium и эмулятором Android

Контейнер запущен, в терминале видим записи, что Appium Server запущен и работает. Можно протестировать соединение. Для этого используем Appium Inspector и отредактируем параметры соединения. Так как в контейнере у нас запущен Appium Server версии 2.19 (то о чем упоминалось ранее), то мы должны изменить путь на http://localhost:4723, убрав /wd/hub/. Затем нужно правильно прописать наименование виртуального устройства, так как оно создано под именем emulator, то к нему еще добавляется порт 5554.  

Подключение Appium Inspector к эмулятору в контейнере
Подключение Appium Inspector к эмулятору в контейнере

Нажимаем Начать сессию и получаем соединение в Appium Server в нашем запущенном контейнере. В инспекторе мы видим открытый экран Settings и можем работать с элементами.

Просмотр системных элементов через Appium Inspector
Просмотр системных элементов через Appium Inspector

А как же быть с тестами в нашем случае? Давайте попробуем запустим тест. Для корректного запуска в тесте нам нужно подправить путь appium_server_url = 'http://localhost:4723', убрав /wd/hub/. Все прекрасно работает.

Запуск тестов на Appium и эмуляторе в нашем контейнере
Запуск тестов на Appium и эмуляторе в нашем контейнере

Настало время проинтегрировать все это в CI/CD GitLab.

Процесс автоматизации и интеграция в CI/CD  

Теперь после того, как была настроена среда для тестирования можно вернуться к непосредственному этапу автоматизации тестирования. Настройки автоматизации обычно прописываются в специальном файле, в частности, для gitlab-ci.yml для GitLab, который описывает, какие задачи и в каком порядке должны выполняться при изменении кода. Но сначала нам нужно залить готовый образ в GitLab репозиторий. Для этого выполняем логинацию в репозитория через access-token и  вводим команду

docker push registry.example.ru/dt_test/mobile:v2.0.0 

Загрузка образа запущена

Загрузка нашего образа в проект GitLab
Загрузка нашего образа в проект GitLab

И наконец, наш образ загружен в проект GitLab

Результат загрузки
Результат загрузки

Подведем итог и определимся с тем какой минимум мы должны загрузить и что должно быть в gitlab-ci.yml. В образе у нас уже есть виртуальное устройство (эмулятор) и он даже запущен, значит осталось через CI/CD загрузить свеженькую версию тестируемого приложения. У нас через скрипт устанавливаются все необходимые пакеты pytest и запускается Appium Server, поэтому достаточно запустить тесты и сохранить результат в артефакты (например, в виде отчета). 

В проект GitLab мы переносим каталог с тестами tests, скрипт start-appium.sh (не забудьте из скрипта start-appium.sh удалить команду ожидания wait). Настраиваем код gitlab-ci.yml:

variables:

  APK_NAME: cryptoarm-1.0.30.apk

  APK_PATH: https://ftp.digt.ru/web/PublicReleases/CryptoARM_Mobile/v1.0.30/${APK_NAME}

stages:

  - build_test

  - send_report

build_test:

  stage: build_test

  image: registry.example.ru/dt_test/mobile:v2.0.0

  script:

    - chmod +x start-appium.sh 

    - ./start-appium.sh        

    - sleep 2

    - |

      for i in {1..20}; do

        if curl -s http://localhost:4723/status | grep -q '"ready"[[:space:]]*:[[:space:]]*true'; then

          echo "✅ Appium готов"; break

        fi

        echo "⏳ Appium не готов, подождём..."; sleep 5

      done

    - wget ${APK_PATH};

    - echo "Устанавливаем приложение ${APK_NAME}"

    - adb install -d ${APK_NAME};

    - pytest tests/system.py tests/install.py --html=report.html

    - REPORT_URL=https://git.example.ru/dt_test/mobile/-/jobs/${CI_JOB_ID}/artifacts/download

    - echo "REPORT_URL=https://git.example.ru/dt_test/mobile/-/jobs/${CI_JOB_ID}/artifacts/download" > report_url.env

  tags:

    - autotesting

  when: always

  artifacts:

    when: always

    paths:

      - report.html 

      - report_url.env 

    reports:

      junit: report.html

    expire_in: 2 day

  allow_failure: false

send_report:

  stage: send_report

  image: alpine:3.21.2

  dependencies:

    - build_test

  script: 

    - apk add libxml2-utils jq curl git wget grep

    - ls

    - REPORT_FILE="report.html"

    - if [[ -f "$REPORT_FILE" ]]; then echo "Файл отчета найден"; else echo "Файл отчета не найден"; fi

    - head -n 10 $REPORT_FILE

    - PASSED=$(grep -o '[0-9]\+ Passed,' "$REPORT_FILE" | grep -o '[0-9]\+')

    - FAILED=$(grep -o '[0-9]\+ Failed,' "$REPORT_FILE" | grep -o '[0-9]\+')

    - SKIPPED=$(grep -o '[0-9]\+ Skipped,' "$REPORT_FILE" | grep -o '[0-9]\+')

    - TOTAL=$((PASSED + FAILED + SKIPPED))

    - FAIL=$FAILED  # Определение переменной FAIL

    - if [ "$FAIL" -ne 0 ]; then STATUS="🔴 FAIL"; else STATUS="🟢 PASS"; fi

    - LAST_UPDATE=$(git log origin/test -1 --format="%cd" --date=format:"%d-%m-%Y %H:%M:%S" -- tests)

    - echo "LAST_UPDATE:" $LAST_UPDATE

    - echo "VERSION_APK:" $VERSION

    - echo "APK_PATH:" $APK_PATH

    - source report_url.env

    - echo "REPORTY_URL:" $REPORT_URL

    - echo "Total:" $TOTAL

    - echo "Passed:" $PASSED

    - echo "Failed:" $FAILED

    - echo "Skipped:" $SKIPPED 

    # Отправка сообщения в bitrix чат

    - |  

      curl -X POST "https://crm.digtlab.ru/rest/XXX/XXX/im.message.add.json" \

      --data-urlencode "MESSAGE=📊 [B]Отчет по тестированию новой версии[/B] 📊 [BR]Версия КриптоАРМ Mobile: [B]${VERSION}[/B][BR]Путь к дистрибутиву: [B]${APK_PATH}[/B][BR]Дата последнего обновления тестов: [B]${LAST_UPDATE}[/B][BR]Ссылка на результаты тестирования: [B][URL]${REPORT_URL}[/URL][/B][BR]Статус: [B]${STATUS}[/B][BR]Всего тестов: [B]${TOTAL}[/B][BR]Успешно: [B]${PASSED}[/B][BR]Провалено: [B]${FAILED}[/B][BR]Пропущено: [B]${SKIPPED}[/B]" \

      -d "DIALOG_ID=XXX" \

      -d "SYSTEM=Y"

  needs: ["build_test"]

  tags:

    - autotesting

  when: always

Запускаем конвейер и получаем наш долгожданный результат в канале Битрикс.

Отчет о тестировании в канале Битрикс, сформированный через CI/CD проекта GitLab
Отчет о тестировании в канале Битрикс, сформированный через CI/CD проекта GitLab

Да, еще есть особенность в организации runner’a проекта. Сервер должен использовать виртуализацию на основе KVM (Kernel-based Virtual Machine), что позволяет запускать виртуальные машины (ВМ) на хосте. Модуль KVM должен быть загружен в конфигурации сервера, чтобы обеспечить поддержку виртуализации. Раннер (например, CI/CD раннер или другой сервис) запускается в привилегированном режиме, что дает ему доступ к ресурсам хоста и позволяет выполнять задачи, требующие повышенных прав.

Послесловие

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

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

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

Tags:
Hubs:
+2
Comments2

Articles