
О чём эта статья?
Всем привет, меня зовут Кирилл и я Android-разработчик в Scanny. В прошлой статье, мы описали то, как будет выглядеть наш CI/CD, научились запускать статический анализатор кода, выполнять Unit-тестирование, собирать различные Build Flavors и отправлять их в нашу Telegram-группу.
В этой статье я покажу, как можно подключить и запустить Android-тесты в рамках CI/CD на примере Marathon Labs и Firebase Test Lab.
Цикл статей про CI/CD для Android состоит из:
Вы находитесь здесь.
Настраиваем CI/CD Android-проекта, часть 3. Автоматизация публикации версий в Play Market.
Marathon Labs
Начнем наше Android-тестирование с Marathon Labs. Для начала регистрируемся на Marathon Labs Cloud и переходим в раздел с токенами.

После чего создаем новый токен доступа, он нам понадобится для того, чтобы связать наш CI/CD с Marathon Labs. Сам токен сохраняем в надежном месте.

Далее переходим в раздел с проектами и создаем новый проект, даем ему название и slug, он нам понадобится, чтобы потом привязать наши тесты к рабочему проекту. Этот этап опциональный, мы просто делаем это для удобства.

На этом подготовка заканчивается, осталось написать скрипт, который будет отправлять наши сборки на тестирование в Marathon Cloud.
runAndroidTestsUsingMarathon:
stage: tests
script:
- ./gradlew app:assembleSomeBuildFlavorDebug
- ./gradlew app:assembleSomeBuildFlavorDebugAndroidTest
- VERSION="1.0.46"
- curl --location https://github.com/MarathonLabs/marathon-cloud-cli/releases/download/${VERSION}/marathon-cloud-v${VERSION}-{the archive we need} --output /tmp/marathon-cloud
- mkdir -p /marathon
- tar -xzf /tmp/marathon-cloud --directory /marathon
- mv /marathon/marathon-cloud-v${VERSION}-{the archive we need}/marathon-cloud /usr/local/bin/
- chmod +x /usr/local/bin/marathon-cloud
- marathon-cloud devices android
- marathon-cloud run android --application "app/build/outputs/apk/{build flavor name}/debug/{your apk's name}.apk" --test-application "app/build/outputs/apk/androidTest/{build flavor name}/debug/{your apk's name}-androidTest.apk" --name ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} --project ${MARATHON_CLOUD_PROJECT_ID}
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
Здесь мы собираем APK приложения, и тестовый APK.
./gradlew app:assembleSomeBuildFlavorDebug
./gradlew app:assembleSomeBuildFlavorDebugAndroidTest
Скачиваем Marathon Cloud CLI и сохраняем в указанную директорию.
- VERSION="1.0.46"
- curl --location https://github.com/MarathonLabs/marathon-cloud-cli/releases/download/${VERSION}/marathon-cloud-v${VERSION}-{the archive we need} --output /tmp/marathon-cloud
Создаем новую директорию, куда будем распаковывать наш архив.
- mkdir -p /marathon
И непосредственно распаковываем в эту директорию.
- tar -xzf /tmp/marathon-cloud --directory /marathon
Перемещаем бинарный файл marathon-cloud в системную директорию /usr/local/bin/
.
- mv /marathon/marathon-cloud-v${VERSION}-{the archive we need}/marathon-cloud /usr/local/bin/
Устанавливаем права на исполнение для marathon-cloud
.
- chmod +x /usr/local/bin/marathon-cloud
Печатаем в консоль список доступных устройств, на которых мы можем запускать наши тесты. Делать это не обязательно.
- marathon-cloud devices android
И наконец, запускаем наши тесты.
- marathon-cloud run android --application "app/build/outputs/apk/{build flavor name}/debug/{your apk's name}.apk" --test-application "app/build/outputs/apk/androidTest/{build flavor name}/debug/{your apk's name}-androidTest.apk" --name ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME} --project ${MARATHON_CLOUD_PROJECT_ID}
Где мы даем название для нашего теста, в данном случае имя ветки из нашего MR.
--name ${CI_MERGE_REQUEST_SOURCE_BRANCH_NAME}
И указываем slug
нашего проекта, чтобы привязать тесты к конкретному проекту.
--project ${MARATHON_CLOUD_PROJECT_ID}
ВАЖНО
Здесь, при работе сmarathon-cloud
мы не использовали команду--api-key
, которая требует наш сгенерированный токен. Дело в том, что если мы определим переменную с названиемMARATHON_CLOUD_API_KEY
, то Marathon автоматически будет использовать ее, а значит нам не нужно каждый раз его указывать при работе сmarathon-cloud
.Дополнительно напоминаю, что чувствительные секреты (токены, ключи и т.д.) лучше хранить за пределами Gitlab variables. Как пример, можно использовать Yandex Lockbox, Google Cloud Secret Manager или HashiCorp Vault.
Переменные окружения:
Название переменной |
Описание |
---|---|
MARATHON_CLOUD_API_KEY |
Наш токен, который мы сгенерировали ранее |
MARATHON_CLOUD_PROJECT_ID |
Slug проекта, который мы создавали ранее |
CI_MERGE_REQUEST_SOURCE_BRANCH_NAME |
Название ветки из нашего MR, подробнее тут |
В целом на этом все, итогом имеем такую красоту.

Firebase Test Lab
Внимание, данные шаги описаны исходя из того, что Firebase
уже подключен к проекту. С первоначальной настройкой Firebase будет немного посложнее, но делается это всего 1 раз.
В первую очередь в Google Cloud, необходимо подключить следующие 3 API в консоли разработчика:
Cloud Functions API;
Cloud Testing API;
Cloud Tool Results API.
Для этого переходим в раздел APIs & Services
, где в боковом меню ищем пункт Enabled APIs and Services
и переходим туда.

Затем нажимаем на кнопку Enable APIs and Services
и в поисковике вводим названия API, которые я указывал выше, подключаем их. Некоторые из них уже могут быть добавлены.

Далее необходимо создать сервисный аккаунт, который будет использоваться для тестирования. Для этого переходим в раздел IAM & Admin
во вкладку Service Accounts
и нажимаем на кнопку Create service acount
.

В открывшемся окне заполняем название и описание. По поводу названия и описания - тут на ваш вкус и цвет. Далее, в разделе Grant this service account access to project
задаем роль Editor
. 3 шаг заполнять не обязательно.

Теперь необходимо создать JSON-ключ, чтобы связать Google Cloud с нашим CI/CD, для этого переходим в наш сервисный аккаунт.

Открываем вкладку Keys
и нажимаем кнопку Add key
.

Создаем новый ключ, выбираем формат ключа - JSON. После чего скачиваем ключ на наш ПК.

С настройкой все, определим наши переменные для дальнейшего использования.
Переменные окружения:
Название переменной |
Описание |
---|---|
GOOGLE_CLOUD_PROJECT_ID |
Id проекта в google cloud |
SERVICE_ACCOUNT |
JSON-ключ, который мы создали и скачали на предыдущем этапе, этот файл необходимо открыть и без изменений скопировать ключ сюда |
Информацию по GOOGLE_CLOUD_PROJECT_ID
, можно найти следующим образом:

Всё, теперь все подготовительные этапы пройдены и можно перейти к pipeline'ну.
runAndroidTestsUsingFirebase:
stage: tests
script:
- ./gradlew app:assembleSomeBuildFlavorDebug
- ./gradlew app:assembleSomeBuildFlavorDebugAndroidTest
- apt-get update
- apt install python3-pip --yes
- curl https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz --output /tmp/google-cloud-sdk.tar.gz
- mkdir -p /google
- tar zxf /tmp/google-cloud-sdk.tar.gz --directory /google
- /google/google-cloud-sdk/install.sh --quiet
- source /google/google-cloud-sdk/path.bash.inc
- gcloud components update
- gcloud config set project ${GOOGLE_CLOUD_PROJECT_ID}
- echo $SERVICE_ACCOUNT > /tmp/service-account.json
- gcloud auth activate-service-account --key-file /tmp/service-account.json
- gcloud firebase test android models list
- gcloud firebase test android versions list
- gcloud firebase test android run \
--type instrumentation \
--use-orchestrator \
--app app/build/outputs/apk/{build flavor name}/debug/{your apk's name}.apk \
--test app/build/outputs/apk/androidTest/{build flavor name}/debug/{your apk's name}-androidTest.apk \
--device model=Pixel2,version=30,locale=ru,orientation=portrait
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_TARGET_BRANCH_NAME == "master"'
Здесь мы собираем APK приложения, и тестовый APK.
./gradlew app:assembleSomeBuildFlavorDebug
./gradlew app:assembleSomeBuildFlavorDebugAndroidTest
Далее, обновляем списки пакетов, чтобы использовать актуальные версии.
- apt-get update
Устанавливаем python и pip (система управления пакетами). --yes
- чтобы не подтверждать установку вручную.
- apt install python3-pip --yes
Затем скачиваем Google Cloud SDK.
- curl https://dl.google.com/dl/cloudsdk/channels/rapid/google-cloud-sdk.tar.gz --output /tmp/google-cloud-sdk.tar.gz
Создаем новую директорию, куда будем распаковывать наш архив.
- mkdir -p /google
Теперь необходимо распаковать скачанный архив в нашу директорию.
- tar zxf /tmp/google-cloud-sdk.tar.gz --directory /google
И установить данный SDK.
- /google/google-cloud-sdk/install.sh --quiet
Чтобы дальше работать с Google Cloud SDK
из командной строки, загрузим все его переменные окружения и т.д. в наш PATH
(В Linux, здесь система ищет исполняемые файлы, когда мы работаем с ними из командной строки).
- source /google/google-cloud-sdk/path.bash.inc
Теперь начинаем настраивать наш Google Cloud
. Для этого обновим компоненты SDK.
- gcloud components update
Устанавливаем проект, с которым будем работать и который мы настроили до этого.
- gcloud config set project ${GOOGLE_CLOUD_PROJECT_ID}
Авторизуемся.
- echo $SERVICE_ACCOUNT > /tmp/service-account.json
- gcloud auth activate-service-account --key-file /tmp/service-account.json
Опционально печатаем в консоль список доступных устройств, на которых мы можем запускать наши тесты, а так же версии ОС Android, доступные для тестирования.
- gcloud firebase test android models list
- gcloud firebase test android versions list
Заключительным этапом мы уже конфигурируем запуск наших Android-тестов в Firebase. Подробнее про то, как конфигурировать запуск можно прочитать в официальной документации.
- gcloud firebase test android run \
--type instrumentation \
--use-orchestrator \
--app app/build/outputs/apk/{build flavor name}/debug/{your apk's name}.apk \
--test app/build/outputs/apk/androidTest/{build flavor name}/debug/{your apk's name}-androidTest.apk \
--device model=Pixel2.arm,version=30,locale=ru,orientation=portrait
После тестирования будут сформированы отчеты, которые мы сможем просмотреть в консоли разработчика Firebase.


Заключение
Ну вот и все, мы рассмотрели варианты запуска наших Android-тестов с использованием 2-х сервисов: Marathon Labs и Firebase Test Lab. Надеюсь кому-нибудь эта статья поможет.
В следующей части я расскажу про загрузку release-сборок в Play Market, где мы подключим необходимые сервисы и настроим pipeline. Создание тэгов в Gitlab будет в этой же статье. организовывать работу будем на примере 2-х решений: Gradle Play Publisher и Fastlane.
Дополнительно мы соберем свой Docker Image со всем необходимым окружением, и далее будем использовать в нашем CI/CD. Благодаря этому нам не придется каждый раз устанавливать все инструменты (Python, awscli и другие.).
Еще увидимся!