Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Меня зовут Дмитрий, я работаю тестировщиком в компании MEL Science. Совсем недавно я закончил разбираться со сравнительно свежей фичей от Firebase Test Lab — а именно, с инструментальным тестированием iOS приложений с использованием нативного фреймворка тестирования XCUITest.

До этого я уже распробовал Firebase Test Lab для Android и мне все очень понравилось, так что я решил попробовать поставить тестовую инфраструктуру iOS проекта на те же рельсы. Приходилось очень много гуглить и не все получалось с первого раза, поэтому я решил написать статью-туториал для тех, кому все еще это предстоит.

Итак, если у вас есть UI тесты на iOS проекте, вы сможете уже сегодня попробовать запустить их на реальных девайсах, любезно предоставленных Корпорацией Добра. Заинтересованным — добро пожаловать под кат.

В повествовании я решил отталкиваться от некоторых исходных данных — приватный репозиторий на GitHub и система сборки CircleCI. Название приложения — AmazingApp, bundleID — com.company.amazingapp. Эти данные я привожу сразу, для уменьшения последующей путаницы.

Если те или иные решения в своем проекте вы реализовали по-другому — делитесь опытом в комментариях.

1. Сами тесты

Создаем новую ветку проекта для UI тестов:

$ git checkout develop
$ git pull
$ git checkout -b “feature/add-ui-tests”

Откроем проект в XCode и создадим новую Цель (Target) с UI тестами [XCode -> File -> New -> Target -> iOS Testing Bundle], даем ей говорящее название AmazingAppUITests.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Переходим в секцию Build Phases созданного Target и проверяем наличие Target Dependencies — AmazingApp, в Compile Sources — AmazingAppUITests.swift.

Хорошей практикой является выделение различных вариантов сборки в отдельные Схемы (Schemes). Создаем схему для наших UI тестов [XCode -> Product -> Scheme -> New Scheme] и даем ей такое же название: AmazingAppUITests.

Build созданной схемы должен включать в себя Target основного приложения — AmazingApp и Target UI тестов — AmazingAppUITests — см.скриншот

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Далее, создаем новую конфигурацию сборки для UI тестов. В XCode кликаем по файлу проекта, переходим в секцию Info. Кликаем на “+” и создаем новую конфигурацию, например XCtest. Это потребуется нам в дальнейшем, дабы избежать плясок с бубном когда дело дойдет до code signing.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

В вашем проекте есть по крайней мере три Target: основное приложение, юнит тесты (ведь они есть, не так ли?) и созданный нами Target UI тестов.

Заходим в Target AmazingApp, вкладка Build Settings, раздел Code Signing Identity. Для конфигурации XCtest выбираем iOS Developer. В разделе Code Signing Style выбираем Manual. Provisioning profile мы еще не сгенерировали, но чуть позже обязательно к нему вернемся.

Для Target AmazingAppUITests делаем то же самое, но в графу Product Bundle Identifier вписываем com.company.amazingappuitests.

2. Настройка проекта в Apple Developer Program

Заходим на страницу Apple Developer Program, переходим в раздел Certificates, Identifiers & Profiles и затем в графу App IDs пункта Identifiers. Создаем новый App ID с именем AmazingAppUITests и bundleID com.company.amazingappuitests.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Теперь у нас есть возможность подписывать наши тесты отдельным сертификатом, но… Процедура сборки билда для тестирования подразумевает сборку самого приложения и сборки раннера тестов. Соответственно, мы сталкиваемся с проблемой подписи двух bundle ID одним provisioning profile. Благо, существует простое и элегантное решение — Wildcard App ID. Повторяем процедуру создания нового App ID, но вместо Explicit App ID выбираем Wildcard App ID как на скриншоте.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

На этом этапе работа с developer.apple.com окончена, но сворачивать окно браузера мы не будем. Идем на сайт с документацией по Fastlane и читаем про утилиту Match от корки до корки.

Внимательный читатель заметил, что для использования этой утилиты нам понадобится приватный репозиторий и аккаунт, имеющий доступ как к Apple Developer Program, так и к Github. Создаем (если вдруг такого нет) аккаунт вида [email protected], придумываем мощный пароль, регистрируем его в developer.apple.com, назначаем администратором проекта. Далее, даем аккаунту доступ к github репозиторию вашей компании и создаем новый приватный репозиторий с именем вроде AmazingAppMatch.

3. Настройка Fastlane и утилиты match

Открываем терминал, переходим в папку с проектом и инициализируем fastlane как указано в официальном мануале. После ввода команды

$ fastlane init

будет предложено выбрать доступные конфигурации использования. Выбираем четвертый пункт — ручная настройка проекта.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

В проекте появилась новая директория fastlane, в которой лежат два файла — Appfile и Fastfile. В двух словах — в Appfile мы храним служебные данные, а в Fastfile прописываем jobs, в терминологии Fastlane именуемые lanes. Рекомендую к прочтению официальную документацию: раз, два.

Открываем Appfile в любимом текстовом редакторе и приводим его к следующему виду:

app_identifier "com.company.amazingapp"       # Bundle ID
apple_dev_portal_id "[email protected]"  # Созданный инфраструктурный аккаунт, имеющий право на редактирование iOS проекта в Apple Developer Program.
team_id "LSDY3IFJAY9" # Your Developer Portal Team ID

Возвращаемся в терминал и по официальному мануалу начинаем настраивать match.

$ fastlane match init
$ fastlane match development

Далее вводим запрашиваемые данные — репозиторий, аккаунт, пароль и т.д.

Важно: при первом запуске утилита match попросит ввести пароль для дешифровки репозитория. Очень важно сохранить этот пароль, на этапе настройки CI сервера он нам пригодится!

В папке fastlane появился новый файл — Matchfile. Открываем в любимом текстовом редакторе и приводим к виду:

git_url("https://github.com/YourCompany/AmazingAppMatch") #Созданный приватный репозиторий для хранения сертификатов и профайлов.
type("development") # The default type, can be: appstore, adhoc, enterprise or development
app_identifier("com.company.amazingapp")
username("[email protected]") # Your Infrastructure account Apple Developer Portal username

Заполняем именно таким образом, если хотим в дальнейшем использовать match для подписи билдов для выкладки в Crashlytics и/или AppStore, т.е для подписи bundle ID вашего приложения.

Но, как мы помним, для подписи тестового билда мы создали специальный Wildcard ID. Поэтому, открываем Fastfile и вписываем новый lane:

lane :testing_build_for_firebase do

    match(
      type: "development",
      readonly: true,
      app_identifier: "com.company.*",
      git_branch: "uitests"  # создаем отдельный бранч для development сертификата для подписи тестовой сборки.
    )

end

Сохраняем, вводим в терминал

fastlane testing_build_for_firebase

и видим как fastlane создал новый сертификат и положил его в репозиторий. Отлично!

Открываем XCode. Теперь у нас есть нужный provisioning profile вида Match Development com.company.*, который нужно указать в секции Provisioning profile для таргетов AmazingApp и AmazingAppUITests.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Осталось дописать lane для сборки тестов. Идем в репозиторий проекта плагина для fastlane, облегчающего настройку экспорта в Firebase Test Lab и следуем инструкциям.

Копипастим из исходного примера, чтобы наш lane testing_build_for_firebase в итоге выглядел так:


 lane :testing_build_for_firebase do

    match(
      type: "development",
      readonly: true,
      app_identifier: "com.company.*",
      git_branch: "uitests"
    )

    scan(
      scheme: 'AmazingAppUITests',      # UI Test scheme
      clean: true,                        # Recommended: This would ensure the build would not include unnecessary files
      skip_detect_devices: true,          # Required
      build_for_testing: true,            # Required
      sdk: 'iphoneos',                    # Required
      should_zip_build_products: true,     # Must be true to set the correct format for Firebase Test Lab
    )

    firebase_test_lab_ios_xctest(
      gcp_project: 'AmazingAppUITests', # Your Google Cloud project name (к этой строчке вернемся позже)
      devices: [                          # Device(s) to run tests on
        {
          ios_model_id: 'iphonex',        # Device model ID, see gcloud command above
          ios_version_id: '12.0',         # iOS version ID, see gcloud command above
          locale: 'en_US',                # Optional: default to en_US if not set
          orientation: 'portrait'         # Optional: default to portrait if not set
        }
      ]
    )

  end

Для получения полной информации о настройке fastlane в CircleCI рекомендую к прочтению официальную документацию раз, два.

Не забываем дополнить наш config.yml новой задачей:

build-for-firebase-test-lab:
   macos:
     xcode: "10.1.0"   
   working_directory: ~/project
   shell: /bin/bash --login -o pipefail
   steps:
     - checkout
     - attach_workspace:
         at: ~/project
     - run: sudo bundle install     # обновляем зависимости
     - run:
         name: install gcloud-sdk   # на mac машину необходимо установить gcloud
         command: |
           ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" < /dev/null 2> /dev/null ; brew install caskroom/cask/brew-cask 2> /dev/null
           brew cask install google-cloud-sdk
     - run:
         name: build app for testing
         command: fastlane testing_build_for_firebase  # запускаем lane сборки и отправки в firebase

4. А как же наш тестовый стенд? Настраиваем Firebase.

Приступим, собственно, к тому, для чего статья и писалась.

Возможно, ваше приложение использует Firebase на бесплатном тарифном плане, возможно — не использует вовсе. Принципиальной разницы абсолютно нет, потому как для нужд тестирования мы можем создать отдельный проект с годом бесплатного использования (круто, да?)

Логинимся в наш инфраструктурный аккаунт (или любой другой, без разницы), и идем на страницу консоли Firebase. Создаем новый проект с именем AmazingAppUITests.

Важно: В предыдущем шаге в Fastfile в lane firebase_test_lab_ios_xctest параметр gcp_project должен соответствовать названию проекта.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Дефолтные настройки нас вполне устраивают.

Не закрываем вкладку, под тем же аккаунтом регистрируемся в Gcloud — это вынужденная мера, так как общение с Firebase происходит с помощью интерфейса консоли gcloud.

Google дарит 300$ на год, что в контексте выполнения автотестов эквивалентно году бесплатного использования сервиса. Вводим платежные данные, дожидаемся тестового списания 1$ и получаем 300$ на счет. По прошествии года проект будет автоматически переведен на бесплатный тарифный план, так что волноваться о возможной потере денег не стоит.

Вернемся на вкладку с проектом Firebase и переведем его на тарифный план Blaze — теперь нам есть чем платить в случае превышения лимита.

В интерфейсе gcloud выбираем наш Firebase проект, выбираем пункт главного меню «Каталог» и добавляем Cloud Testing API и Cloud Tools Result API.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Затем переходим в пункт меню «IAM и администрирование» -> Сервисные аккаунты -> Создать сервисный аккаунт. Выдаем права на редактирование проекта.

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Создаем API ключ в формате JSON

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект

Скачанный JSON понадобится нам чуть позже, а пока настройку Test Lab будем считать оконченной.

5. Настройка CircleCI

Назревает резонный вопрос — а что делать с паролями? Надежно сохранить наши пароли и прочие чувствительные данные нам поможет механизм переменных окружения нашей билд-машины. В настройках проекта CircleCI выбираем Environment Variables

Запускаем инструментальные тесты в Firebase Test Lab. Часть 1: iOS проект
И заводим следующие переменные:

  • key: GOOGLE_APPLICATION_CREDENTIALS
    value: содержимое json файла ключа сервисного аккаунта gcloud
  • key: MATCH_PASSWORD
    value: пароль для дешифровки github репозитория с сертификатами
  • key: FASTLANE_PASSWORD
    value: пароль инфраструктурного аккаунта Apple Developer Portal

Сохраняем изменения, создаем PR и отправляем на review своему тимлиду.

Итоги

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

Вторая часть будет посвящена пошаговой настройке Firebase Test Lab для Android проекта.

Источник: habr.com

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