
Привет, меня зовут Смирнов Владимир, и я отвечаю за тестирование торгового бэкенда в EXANTE. Разработка кипит, регрессионные наборы автотестов растут — всё это сопровождается хаосом и различиями тестовых окружений, из-за чего неизбежно растёт и число нестабильных падений (ака флаки), за завесой которых могут теряться реальные проблемы. Как мы регулярно поддерживаем автотесты в приемлемом состоянии и стараемся не тратить на это слишком много времени? Об этом и поговорим.
Что происходит?
Как говорилось в предыдущей статье: написание как минимум одного автотеста на задачу является обязательной частью процесса тестирования у нас в EXANTE. Речь идёт о сервисных тестах: которые взаимодействуют с API конкретного микросервиса, существующего в живой среде со всеми её зависимостями. В текущей реальности одним тестом на фичу дело, конечно, не ограничивается: они пишутся пачками.
Но много не только тестов, но и тестовых джоб. У каждой команды несколько микросервисов, на каждый из которых существует джоба в CI/CD. Некоторые сервисы оказались жирноваты на функционал, но в ожидании распила, обзавелись огромным набором тестов. Мы уже выносим часть его в отдельные джобы — и некоторые из них прогоняются и напротив монолита, и напротив нового сервиса. Отдельные джобы тестируют особенности конфигурации сервиса на другом его инстансе. Есть функционал, который нельзя запускать в параллель — приходится выносить его в отдельную джобу и запускать отдельно от всех.
Кроме того, есть разные причины для запуска тестов: изменения в мёрдж-реквесте, ночные прогоны, приёмка при выкатке. Это закономерно ведёт к перманентному росту количества запусков на различных окружениях. Мы ускоряем их работу, оптимизируя, изолируя и запуская в параллель. Но вместе с тем и увеличивается количество нестабильных падений разных тестов на разных окружениях в разных ситуациях.
Причины падения могут быть любыми: как независящими от тестируемого сервиса, например особенности конфигурирования среды, которые мы не учли, или конфликты параллельно запускаемых тестов, так и вполне имеющими к нему отношение: гонка, зависимости от других сервисов и тому подобное.
Закрывая глаза на отдельные падения, просто повторно запустив тесты или того хуже — навесив ретрай, мы рискуем обрести вроде бы хорошее покрытие, но с не очень понятным результатом. Можно ли доверять регрессу, в котором часть тестов нерегулярно падает по неизвестным нам причинам?
Но самое опасное что, устав от малозначительных ошибок, мы рискуем пропустить действительно важные.
И что делать?
Всё это приводит к мысли, что регрессионному набору автотестов требуется постоянное техобслуживание для поддержания его работоспособности. Поддержка набора автотестов — это отдельное направление в работе, которое не должно смешиваться с разработкой нового функционала, на него выделяется постоянное время из капасити спринта и специальный человек (дежурный). Задачи ни в коем случае не должны попадать в общий бэклог — они неизбежно проиграют в приоритетности бизнесу.
Гладко на бумаге
Окей, мы договорились с командой, выделили время в спринте, назначили дежурного, которого не грузим бизнес-задачами. Вот он открывает результаты ночных прогонов на окружении и начинает копать. Тут то и возникают минусы, которые заставляют скептически относиться к этому процессу: мы начинаем много времени тратить на дебаг и анализ падений, пытаясь раскопать их причины, и не успеваем чинить один, как на смену ему появляются новых два. Чиним 1 тест из 10, потратив на него неделю, и экстраполируем эту “эффективность” на оставшиеся поломки. Это сильно демотивирует. А пробегаясь по одним и тем же падениям каждое утро, мы замыливаем глаза. Как же выйти из этого порочного круга и чувствовать результат?

Концепция
Сделаем небольшое философское отступление. Для чего нам нужны автотесты? Очевидно, что первое, что приходит на ум: сэкономить наше время при проведении очередной проверки на регресс. Хорошо, переформулирую вопрос: какими они должны быть? Очевидно, что быстрыми и с широким покрытием, стремящимся к 100%. Окей, а что они должны делать? Очевидно, что должны проходить и всегда быть зелёными!
Вот тут как раз скрыта сложность: такое отношение к тестам приводит не к их починке, а к маскировке других проблем.
Тесты не нужны нам зелёными.
Сначала нужно осознать одну простую вещь (которая очевидна, но на практике почему-то не всем), перевернув понимание необходимости автотестов: они нужны нам не для того, чтобы проходить — они нужны нам для того, чтобы падать. Но! Падать так, чтобы вовремя и конкретно указывать на действительно важные проблемы.
Автотесты — не священная корова, которую нельзя трогать. И не золото, которое надо копить. Это индикаторы, которые могут либо предупреждать нас, либо бесполезно рябить в глазах. Автотесты — инструмент, который приносит пользу, экономит наши силы и время, но в случае поломки — его спокойно можно выбросить или заменить.

Учитывая всё сказанное, мы изменили работу дежурного по поддержке автотестов и разбили её на несколько шагов
Шаг 1: Управляем Приоритетами
Ознакомившись с падениями, нужно выбрать тест для починки: нотификации о результатах прогонов уже сами подсказывают, за что взяться в первую очередь.
В пайплайне тестовой джобы есть отдельные стадии:
-
Стадия доступности сервиса (хэлсчеки, ведь нет смысла запускать тесты, если сервис не доступен),
-
Стадия смоков (многие предустановки данных зависят от базовых API, так что имеет смысл самые используемые эндпойнты проверить отдельно, чтобы избежать каскадных падений)
-
И, собственно, стадия регресса.
Сообщение о падении на конкретной стадии сразу указывает на его критичность.
Сообщение о результатах прогона включает в себя не только количество упавших тестов, но и дополнительную информацию: сколько тестов и по каким причинам не было запущено, какие тесты упали из-за проблем с предустановкой данных, были ли проблемы с их очисткой.
Известные нам флаки мы помечаем специальной маркой. Тест перезапускается только при совпадении ошибки, указанной в описании. В случае прохождения теста при повторном запуске — он отдельно упоминается в нотификации.
У нас также есть отдельный скрипт, который анализирует историю падений тестов и сообщает о повторяющихся изо дня в день. Он позволяет не пропустить что-то, что падает стабильно, но по какой-то причине было не замечено ранее.
Таким образом начало дежурства включает в себя:
-
Беглый анализ по приоритетам, разбиение на группы: критикал, быстрые решения, на исследование.
-
После чего происходит заведение багов, запросы командам (инфраструктуры, смежным), обсуждение на дейлике возникших вопросов.
-
Расстановка марок с указанием заведённых задач: xfail, skipif, skip, rerun_for, которые автомёржятся без необходимости получения аппрува. Это позволяет команде не отвлекаться на эти падения в течение рабочего дня.
Шаг 2: Быстрые Решения
Разобрались с тем, что выглядит критично, и понятно, куда уходят корни проблем. Что делать с оставшимися кейсами, причины падений которых покрыты туманом? Нет, не погружаться в их анализ — мы всё ещё стремимся экономить время. В дело вступает следующий алгоритм:
-
А нужен ли тест? Действительно ли он проверяет что-то важное? Нет ли других (стабильных) тестов, которые упадут при проявлении такой же проблемы, которую покрывает данный тест? Может быть можно просто выключить его? Например, тест на сервис, который больше не разрабатывается.
-
Хорошо, он нужен. А не слишком ли он сложен? Можно ли упростить его, максимально изолировав? Делать это легче, создавая новый тест, чем переписывая старый. Проверьте, действительно ли старый тест повторяет реальный путь системы? У нас были кейсы, когда промежуточный результат тест брал данные совсем не из того сервиса, из которого его получал сервис тестируемый — от этого всякие гонки и задержки, приводящие к непостоянным падениям.
Как я писал выше: автотесты — не священная корова. Тот, кто написал его ранее, пусть даже вы — на тот момент могли ещё просто могли не уметь их писать или не обладали более широким пониманием системы.
-
Не стоит сразу бросаться в дебри логов и эксперименты с воспроизведением падения. Сделайте ассёрты более информативными, добавьте логирование, специальные теги для отслеживания в логах, проверьте, покрыты ли все инструкции шагами (в случае наличия репортинга). После нескольких очередных падений это даст больше стартовой информации, чтобы приступить к действительно пристальному дебагу
-
Кроме того падения анализируются специальным AI-ботом, который предлагает свои варианты решения на основе полученных данных из allure-репорта и анализа кода.
Шаг 3: Исследование и Сотрудничество
Ну вот наконец-то можно и приступить к старому-доброму дебагу-копанию. Но и здесь стоит применить подход, не позволяющий утонуть в потоке ускользающего времени.
Алгоритм выглядит следующим образом:
-
Анализ: выделяем пару часов на первичный анализ теста и сбор информации по возможным причинам падения;
-
Кооперация: созваниваемся с тем, с кем имеет смысл поделиться информацией — тимлид, дежурный из другой команды, или инфраструктура — зависит от результатов анализа. Совместно вырабатываем гипотезу или несколько: ценность именно в возможности получить сторонний взгляд снаружи, не сфокусированный на деталях и не упускающий из вида слона;
-
Проверка гипотез: экспериментируем, получаем новые вводные;
-
Подведение итогов: снова созваниваемся, чтобы определиться, какое решение в итоге можно применить;
-
Реализация: фиксируем решение. Оно может быть неокончательным, но приближает нас к более изолированному и стабильному состоянию..
С каждой итерацией вводной и проверенной информации становится больше, что позволяет совместно выработать максимально адекватное решение за минимальное время.
Удалять ли Старые Кейсы?
Тесты, которые были выключены, не теряются. Специальный скрипт собирает их, проверяет изменение статуса задач (линтер не позволяет проставлять марки без задачи) и сообщает, к каким из них нужно вернуться в случае изменения статуса на закрытый.
Что теперь делать с громоздкими тестами, которым написана более простая альтернатива? Которые написаны “неправильно”? Смело удалять. Или?..
Я снова переверну всё с ног на голову и выскажусь в их защиту. Если у вас есть время — не удаляйте их.
Когда ваш регрессионный тест-сьют будет падать исключительно по делу, моментально давая вам обратную связь по ломающим нововведениям — займитесь отключёнными тестами. Они — источник странного и непредсказуемого поведения, которое позволяет узнать больше неочевидных деталей устройства тестируемой системы.
Например, мы выяснили, что один из наших промежуточных сервисов, подгоняемый запросами клиента (теста), так спешил с изменением ещё не выставленной заявки, что ломал её саму. Создавая “правильные” тесты мы бы вряд ли задумались сэмулировать такую ситуацию, ведь ситуация выстреливала не всегда. Но благодаря небрежному тесту с элементом случайности мы обогатились ещё одним кейсом.
Резюме
Инструмент — не самоцель. Он служит конкретным задачам. Автотест — это инструмент. Его задача: быстро доставлять информацию о деградации функционала тестируемого сервиса. Для поддержания его в адекватном состоянии необходимо:
-
Фильтровать и приоритезировать информацию о падениях: удалять из неё шум — это позволит снять когнитивную нагрузку с человека.
-
Применять простые быстрые решения, улучшающие тесты итеративно.
-
Ограничивать время на решение проблем.
И, самое важное, делать это постоянно, не откладывая в бэклог. Это отдельный процесс, параллельный разработке функционала.
Применяя данный подход, мы ускорили “позеленение” тестов, а каждое новое падение для нас чаще сигнал о состоянии сервиса и окружения, чем загадка, тайна и Бермудский треугольник, поглощающий время сотрудников.
ссылка на оригинал статьи https://habr.com/ru/articles/1032868/