Карантин UI-тестов в iOS |
14.06.2024 00:00 |
Автор: Тимур Шафигуллин
Всем привет! Я Тимур — iOS разработчик в платформенной команде hh.ru. Сегодня я расскажу о нестабильных UI-тестах в iOS, и как мы с ними справляемся. Мы уделяем массу внимания UI-тестам, ведь именно они обеспечивают качество и стабильность в наших iOS-приложениях. Сейчас у нас включено около 600 UI-тестов: они гоняются утром, вечером и на каждом PR в develop. О том, как мы обеспечиваем качество мобильной разработки есть отдельная статья. Рано или поздно большое количество UI-тестов скорее всего начнут тормозить разработку, потому что их стабильность зависит от множества факторов: стенды (API), инфраструктура (обновление Xcode, машин, СI), кодовая база. Даже из‑за проблем в самом XCUITest тесты могут начать выдавать аномалии. Бесконечный ретрай Чтобы отдать готовую задачу в тестирование QA, необходимо пройти следующий процесс: После завершения задачи, нужно открыть Pull Request в develop. На этом этапе выполняется сборка AdHoc приложений и отправка их в TestFlight, а также запуск регресса (Unit + UI-тесты). QA может взять задачу в тестирование, не дожидаясь окончательного прогона UI-теста, но попасть в develop, разумеется, можно только с зеленым регрессом. Здесь можно очутиться в неудобной ситуации — падает UI-тест на функциональность, который никак не был затронут в задаче. Что делает разработчик в такой ситуации? Запускает UI-тесты повторно в надежде на флакование, а если и это не помогает, то пишет в чат и ищет коллег с аналогичной проблемой. Чаще всего мы решаем отключить UI-тест, потому что его функциональность можно проверить вручную. Это позволит не блокировать продуктовые задачи и пропускать их в develop.
На сломанный UI-тест заводится задача и попадает в бэклог QA на исследование, исправление и включение теста обратно. Так как количество UI-тестов непрерывно увеличивалось, закономерно появилась нужда в особом механизме, который позволил бы отключать сломанные тесты раньше, чем об этом напишут в чат. Карантин UI тестовИтак, нам нужен карантин UI-тестов, в который помещались бы сломанные тесты, падающие в develop n-раз. По сути, карантинный UI-тест — это то же самое, что и просто отключенный:
Хранение карантинных UI тестов У каждого приложения есть набор тест‑планов, основной состав которого на примере соискательского приложения выглядит так:
Если требуется отключить какой‑то тест, то отключить его нужно в двух местах — ApplicantHH‑UI‑Tests и ApplicantHH‑UI‑Tests‑Smoke. Еще у приложения могут быть отдельные издания, и его тесты тоже попадают в основной тест-план, но по умолчанию они выключены. Таким образом, у нас нет единого источника с отключенными тестами. Поэтому мы решили сделать под карантин отдельные тест-планы, где карантинные тесты будут наоборот включены. На каждом прогоне, где используются UI-тесты, мы будем исключать из прогона все тесты, которые включены в карантинном тест‑плане. Исключение карантинных тестов Исключить тесты достаточно просто — берем список тестов из запускаемого тест‑плана и исключаем оттуда все те, которые включены в карантинном тест‑плане. Получить список тестов из тест‑плана можно через
Теперь мы получаем следующий профит:
Попадание в карантинОбщая схема работы Рассмотрим принцип работы карантина и по каким критериям UI-тесты могут в него попасть: Регрессы До карантина у нас был только один ночной регресс, который запускался в 23:00 и собирал AdHoc сборки, прогонял Unit- и UI-тесты. В случае каких‑либо падений, дежурный с утра разбирался, что пошло не так и какие были причины. С появлением карантина мы добавили утренний регресс, на котором и работает вся схема с карантином, изображенная выше. Различия между утренним и ночным регрессами небольшие, но всё же есть:
Анализ упавших тестов Если на утреннем регрессе упал хотя бы один тест, то мы повторно прогоним каждый по 12 раз. Это позволяет исключить ошибочные флакования. Если тест 12 раз прошел без единого падения, то он не попадает в карантин. В ином случае, тест является потенциальным кандидатом (дальше будет понятно, почему именно потенциальным) на добавление в карантин, так как он упал 6 раз на регрессе + минимум один раз из 12 повторных прогонов. Включение в карантинный тест-план Включить тест в соответствующем тест‑плане не особо сложно, потому что
Создание задач в Jira Чтобы можно было отслеживать прогресс и историю включения/выключения тестов, мы создаем две Jira-задачи — первая на добавление в карантин, вторая на исправление. В описании задачи есть следующие данные:
Пример того, как выглядят итоговые задачи в Jira: Создание PR Добавленные в тест‑план тесты пока находятся локально на CI-джобе. Чтобы изменения вступили в силу для всех, необходимо чтобы новые включенные тесты попали в develop. Для этого создаем ветку с номером Jira-задачи на добавление в карантин и открываем PR в develop. Описание PR такое же, как и в Jira-задаче. Дифф максимально простой и не требует особого ревью: Принятие решения После создания PR отправляет сообщение в канал iOS-уведомлений о том, что были найдены тесты, которые потенциально могут попасть в карантин. Потенциально, потому что итоговое решение — включать ли тест в карантин, принимает дежурный QA, так как UI-тесты и develop это зона ответственности QA. Уже по данным в PR дежурный QA может оценить ситуацию и принять решение. Если вдруг срабатывание было ошибочным, то PR и задачи просто закрываются. В ином случае задача в Jira берется в работу, и новые карантинные тесты вливаются в develop, чтобы не блокировать другие продуктовые задачи в течение дня. После этого можно либо сразу браться за ремонт сломанных тестов, если причина достаточно очевидная, либо передать отвечающему за тест QA и вернуть тест по освобождению ресурсов. Дополнительные кейсы После создания PR мы также записываем данные об упавших тестах в БД: Сегодня мы используем это только для защиты от дублирования: когда на утреннем регрессе упали те же самые тесты, но уже есть созданная для этого задача. В таком случае задача в Jira и PR не будет создаваться повторно, а отправится лишь повторное напоминание сообщением в канал, чтобы дежурный QA обратил внимание на сломанные тесты. Выход из карантинаПроцесс включения теста обратно пока не имеет никакой автоматизации — он полностью ручной. После добавления карантина этот процесс остался неизменным. После исправления теста QA прогоняет его повторно n-раз на CI, чтобы убедиться, что тест стабильный и не флакует. У нас под это есть отдельный план на CI, где можно указать название теста и минимальное количество прогонов. Остается только выключить тест в карантинном тест‑плане и сделать PR в develop. После этого тест вновь будет выполняться на всех регрессах. Следующие шагиВ процессе проработки идеи с карантином было много крутых идей, которые мы бы хотели сделать в обозримом будущем:
ИтогиС новым процессом карантина тестов сообщения о том, что фича не может попасть в develop, на данный момент не появлялись, так как дежурные QA оперативно реагируют утром, просматривают проблемные тесты и отключают их по необходимости. Также появился единый источник правды со всем списком отключенных тестов. По нему, например, можно дополнительно строить графики для мониторинга количества карантинных тестов или прогонять карантинные тесты отдельно. |