🔥

Тред (Александр Крылов)


Всем доброго дня! Сегодня озвучу несколько мыслей об мобильной инфраструктуре. Первое, что приходит в голову, это конечно инструменты для сборки. Чем пользуетесь вы на своих проектах? Всего 4 варианта, постите( Пишите в коментах, если пользуетесь чем-то другим.
🤔 38.5% GitLab
🤔 28.2% GitHub
🤔 15.4% Jenkins
🤔 17.9% Teamcity

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

И я согласен. Очень удобно держать всё в одном месте.

Но, позвольте, поделиться. Вот что я считаю важным для прогонов на CI: Проверка компиляции кода Статический анализ кода Проверка локализаций Прогон Unit тестов Публикация результатов прогона Прогон UI тесты. Всё вышесказанное должно проходить "быстро"

Думаю, что первым пунктом все согласны. Третий опустим, т.к. он подходит для приложения с большим количество локалей. Что на счёт первого, второго и четвертого?
🤔 0.0% Проверка компиляции
🤔 0.0% 1 + Unit-тесты
🤔 100.0% 1+2+ статический анализ

А про прогоны ui-тестов можно поговорить и поподробнее)

Впервые я столкнулся с UI-тестированием, когда меня попросили настроить monkey тест на мобилке.

Андроид в коробке имеет такой функционал. Сейчас не вспомню какой именно командой это делается, но команда одна. И всё что от меня требовалось, это настроить регулярный прогон такого теста на CI.

Это был мой первый месяц работы. И проковырялся я месяц(!), чтобы всё это настроить. Всё получилось)) И сложности были не с запуском простейшей команды, а с настройкой CI-таски и самого телефона.

И всё заработало. Прогон шёл по ночам, а утром можно было посмотреть отчёты по прогону.

Прошло несколько месяцев и эти отчёты, откровенно, стали никому не нужны) Monkey тестирование на неходило никаких проблем с приложением. (Разаботка писала без багов)

Спустя какое-то время об этой сборке забыли и благополучно отключили. Вместо этого отдел тестирования представил первые тесты на Appium.

Это были нелегкие дни) Но спустя пару недель мне удалось завести их на CI. Для этого потребовалось форкнуть проект управляющего android-приложение и внести небольшие правки, чтобы тесты могли получить доступ до вьюх на экране.

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

Всё это время я занимался Android-разработкой, а все активности по CI просто совмещал с основными задачами.

На новый проект мы пришли с Teamcity на Jenkins. Это вроде называется "культурный шок". Сила привычки не даёт нам адекватно воспринимать что-то новое. Особенно, если оно выглядит не так как прежний инструмент.

Несмотря на все возможности и функциональность Jenkins мы решели поднять своё инстанс Teamcity.

Новая команда, новые взгляды. Отдел тестирования заинтересовался espresso. Данный фрэймворк работал в разы быстрее Appium. После нескольких тестовых прогонов мы приняли решение тащить их на CI.

Возможно, на просторах интернета, вы сразу наткнётесь на простую gradle-таску для запуска ui-тестов на подключенном телефоне(эмуляторе). Но ребята сразу сказали, что тестов будет много и стоит задуматься об оркестрации прогонов.

Наш выбор пал на marathon.

В то время он был уже достаточно стабилен (2017) и отвечал основным требованиям, а именно: Разделение общего количество тестов по эмуляторам. Работа с flaky-тестами Автоматический подхват новых девайсов и исключение отвалившихся

Выбор между реальными девайсами и эмуляторами особо не стоял. Девайсы были под рукой из числа тестовых, но на постоянную основу мы их взять не могли. Поэтому мы запускали эмуляторы. Прямо во время прогоно, один за одним и так в общей сложности поднимали 4 эмулятора на один прогон

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

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

Чтобы эмуляторы стратовали быстро, мы собрали очень толстый образ в котором был полностью преднастроенный эмулятор(страна, язык, номер телефона). Дополнительно мы запускали эмулятор, ждали какое-то время, пока все закрузится, останавливали его, и делалит docker-commit

Образ выходил огромный) больше 10Гб, но ресурсы позволяли такую роскошь. А старт эмулятора занимал теперь 1-2 секунды. После этого он полностью был готов к работе.

О том, как развивалась судьба данной "фермы" я постараюсь рассказать завтра. А по тестам, стоит отметить вот что. Это очень долгие прогоны и, думаю, каждый хочет гонять ui-тесты на каждый pull|merge-request.

Конечно, тут напрашивается несколько путей решения: Ускорить проходение самих тестов(убрать задержки, стартовать преднастроенные сценарии). Увеличить количество девайсов Запускать только определённое количество тестов.

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

По второму вроде всё просто, но и сложно одновременно. Запуск большого количества эмуляторов ограничен ресурсами машины, и вы всё равно придёте к вопросу о ферме.

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

Насколько мне известно данный подход имеет название Impact Analysis. Задам вопрос и продолжу повествование) Используете ли вы в своих проектах Impact Analysis?
🤔 50.0% Да
🤔 50.0% Нет
🤔 0.0% Что-то похожее.

Когда мы только начинали, то вдохновились работой ребят из Avito. В частности вот этим докладом. youtu.be/EBO2S9qcp0s

В теории всё очень просто. Кто-то создает pull|merge-request, а дальше по списку: Смотрим на git diff между текущей веткой и основной Находим соответствия между затронутыми файлами и классами, строковыми ресурсами и т.п.

Ищем зависимости в проекте Доходим до фрагментов или активностей.

И тут возникает вопрос как найти зависящие ui-тесты. В докладе раскрыта тема как найти затронутый модуль. И можно просто гнать все тесты в модуле. Если у вас проект хорошо разбит на модули и тесты тоже разнесены по модулям, то этот вариант вам полностью подойдёт.

У нас на тот момент модуляризация только стартовала и ни о каких прогонах на модуль речи быть не могло. Поэтому мы взяли за "минимальную заафекченную единицу" тестовый класс.

Если вы знакомы с espresso в Android, то знаете, что нет прямой связи между фрагментом и ui-тестом. Ребята из Avito добавили id для рутовых вьюх. Мы добавили аннотации к тестовым PageObject'ам, где указывали файлы верстки. Так мы получили связь между фрагментами и тестами

Первую версию тулзы для поиска затронутых тестов мы выкатили спустя 2 недели после начала работ. Тулза умела находить только по затронутым классам. Ни строки ни стили пока не учитывались, это мы доделали позже.

Имея подобный инструмент вкупе с новым железом и достаточным количеством эмуляторов нам удалось запустить прогон ui-тестов на каждоый pullrequest.

К моменту запуска мы имели около 2к ui-тестов. Прогон на 20 эмуляторах занимал почти два часа. Благодаря Impact Analysis прогон ui-тестов в среднем занимал не более 15 минут.

Поправка, бывали случаи, когда нужно было гнать все тесты. К началу запуска полные прогоны занимали больше 80% от общего числа. CI встал колом)) Если анализ не выдавал результата, то мы гнали все тесты.

Тогда мы сделали маппинг файлов, и если оказывалось, что ничего "важного" затронуто не было, то ui-тесты не гнались совсем.

После этих нововведений полные прогоны занимали не больше одного процента от общего количества. В неделю мы фиксировали 200-250 прогонов. Таким простым решением мы сэкономили огромное количество человеко- и машино-часов

Разумеется по ходу построения инфраструктуры страдали обычные разработчики, если не работает CI или, что хуже, он плохо работает, то тратятся бесчётные часы человеческого времени.

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

Иными словами, живи, не причиняя вреда, а тело дано, чтобы действовать... ©7Раса - Samskara

Александр КрыловАлександр Крылов