Описание статьи
Необходимо ли компании выделять компетенции автоматизатора и так ли они уникальны?
В статье описано, как внутри компании при действующих командах автоматизации происходил пересмотр компетенций, в результате которых возник парадокс «Команда есть, а компетенций нет». Результом пересмотра стало то, что команд автоматизации больше нет.
Цель статьи
Рассказать опыт и причины принятия тех или иных решений.
WARNING: Все решения были проработаны в рамках определенной компании, учитывая специфику проектов |
---|
Структура статьи
- Описание тестируемого объекта, проекта, команд;
- Формулирование целей для системы с автотестами и их решение;
- Формулирование компетенций, необходимых для достижения поставленных целей;
- Подведение итогов.
Описание тестируемого объекта, проекта, команд
Стек: С#, SpecFlow(BddFy), Selenium
Тестируемый объект: Системы для автостраховых компаний в Америке. У всех систем есть админки для настройки приложений, rest api, чтобы клиенты могли сами писать порталы, приложение для создания полиса и осуществоения платежей, приложение для генерации отчетов. Все части должны быть покрыты тестами.
До определенного момента команда автоматизации была обособленной, практически не взаимодействующей с другими командами. Перед ней стояла цель максимально покрыть регрессионный набор автотестами, чтобы уменьшить срок проведения полного регресса QA. Перед регрессом создавался тест ран, который должен был пройден для выпуска версии релиза. Результаты прогона автотестов мапились в этот ран. В системе было примерно 4000 кейсов, которые запускались на разных environment. Время полного прогона больше двух суток. Порядка 15% имели статус broken(сломаны по вине автотеста).
Цели
Появилась необходимость в быстрой верификации качества вмерживаемой фиче-ветки в main branch. Отсюда возникли следующие цели:
- Стабильные тесты. Если падают тесты, то это свидетельствует о том, что влитая ветка имеет сломанный функционал и команда, которая вливает/влила, должна её исправить;
- Быстрые тесты. Сократить время прогона до 4 часов. Мы пришли к выводу, что 4 часа на полный прогон тестов допустимое время ожидания (48 изначальных часов — нет).
- Необходимо сделать фундамент под мутационные тесты. Этому будет посвящен отдельный цикл статей
Быстрые и стабильные тесты
Верхнеуровневно я решил объединить два пункта, поскольку увеличения скорости прогона можно добиться за счет параллелизации, а это открывает ящик пандоры с флаки тестами. Ведь, если у вас есть некий статический контекст по типу HttpContext, который хранит информацию о залогиненном юзере и его claims, то при параллельном запуске этот логин будет выполняться для всех запущенных тестов. Что, при определенных условиях, приводит к падениям, которые локально будет довольно сложно воспроизвести. Теперь остановимся на каждом из пунктов поподробней.
Быстрые тесты
Для увеличения скорости прогонов тестов были реализованы следующие подцели:
- Параллельное исполнение тестов;
- Написание эмулятора, который бы напрямую через код мог привести систему к тестируемому состоянию;
В рамках параллельного исполнения тестов были реализованы следующие мероприятия:
- Переписывание CI скриптов. Выбор был сделан в пользу Cake(C# Make), поскольку он использовался в основном приложении и содержал весь необходимый функционал. Добавлена возможность для проброса дополнительного параметра, задающего количество потоков;
- Выкошены практически все статические классы методы, за исключением extension-ов;
- Добавлена связка Selenoid с GoGrid Router – чтобы снизить нагрузку на CI/CD агентах.
В рамках написания эмулятора:
- Перенос проектов автотестов в solution с тестируемым объектом;
- Подключение solution analyzer и исправление варнигов и ошибок;
- Перенос общих частей в MSBuild конфигурации;
- Написание эмулятора.
От себя бы хотелось добавить, что эмулятор писать имеет смысл, если в Controller/ View тестируемого объекта не содержится логики и у приложения есть DI контейнер. В противном случае перед тем, как писать эмулятор, лучше всю логику вынести в сервисы/хэндлеры. Эмулятор позволяет без поднятия браузера или обращения по Rest выполнить нужные действия. Тут я не устану повторять: «данные действия не являются тестируемыми, они лишь приводят систему в тестируемое состояние». Если по сравнению с рест или шиной выигрыш по времени не такой большой, то если сравнивать с UI — выигрыш очень существенный. Вынос повторяемых степов в эмулятор позволил сократить время прогона теста до 5 раз.
Cтабильные тесты
В рамках стабилизации прогона были проведено следующее:
- Использование DI контейнера. DI контейнер стал Must-Have feature после параллелизации, с ним стало возможно управлять скоупами и можно быть уверенным, что разным тестам приедет разная или одна и та же реализация, в зависимости от типа регистрации. Это позволило существенно поднять стабильность и уменьшить стоимость поддержки;
- Отказ от инжектируемого ScenarioContext. Когда много тестов, нужен иммутабельный контекст. Невозможно быть уверенным, что тебе доезжает нужное значение, если есть степы, которые его могут изменить. На что заменили будет подробней рассмотрено в пункте про мутационные тесты;
- Проведение замеров для вычисления оптимальной нагрузки. Для того, чтобы сделать тесты атомарными, были написаны скрипты для клонирования сложных сущностей на уровне БД — при больших нагрузках SQL Server становилось плохо и тесты могли падать;
- Попытались внедрить принципы SOLID насколько сил хватило. Этот пункт влияет на стабильность косвенно, данные принципы помогают убрать дублируемую логику и сделать код более читабельным.
Большую часть времени я был уверен, что нестабильные тесты – вина разработчика (автоматизатора), который их написал. Время показало, что исправить все тесты не получается. Нам удалось исправить 99.9 % тестов, но время, потраченное на увеличение порядка стабильных тестов, увеличивалось экспоненциально. И в один момент мы поняли, что 3 падающих теста на 4000 уже не так критично и их можно пройти руками. Да, так не выйдет сделать полностью автоматическую доставку релиза до staging, но пока это не требуется.
Фундамент под мутационные тесты
На самом деле тут цель сделать тесты расширяемыми: требования к автотестам увеличиваются с течением времени и хочется сделать так, чтобы эти требования можно было удовлетворить минимальными изменениями в коде. И желательно даже сделать так, чтобы это было лишь расширение функционала, а не его изменение. Мутации сценариев – лишь один из возможных сценариев расширения функционала.
Я бы выделил несколько пунктов:
- Реализации шагов должны быть максимально тонкими, чтобы можно было максимально быстро сменить BDD Framework. SpecFlow хороший инструмент, но уж очень медленно он осуществлял миграцию на .net core. Да и если понадобится расширение поведения степа, у SpecFlow есть только хуки, а они удобны не всегда;
- Адаптация CQRS подхода под нужды автоматизации. Получилось разбиение на UserActivity(UserActivity, UserActivityHandler, UserActivityResult) и CheckAssertions (CheckAssertions, CheckAssertionsHandler);
- Реализация Command Dispatcher(Mediator) с возможностью расширения. Это имено та, часть которая отвечает за расширяемость системы.
Для наглядности приведу пример:
Реализация степ биндинга выглядит следующим образом:
Медиатор находит подходящий UserActivityHander и вызывает у него Handle:
Но, поскольку Command Dispatcher расширяемый, следовательно можно:
- Перед вызовом Handle найти валидаторы, которые проверяли, что система находится в
валидном состоянии; - Сохранять результаты всех UserActivity в отдельный контекст, который инициализируется для каждого теста.
Все это позволяет быть уверенным, что если появятся новые требования (например, формирование популяций для мутаций) систему не придется переписывать, а просто появится новое поведение.
Компетенции
После того, как руководители отделов составили матрицы компетенций, выяснилось что компетенции, которые требовались автоматизаторам, большей частью повторялись с компетенциями разработчиков(CLR, принципы разработки ПО, паттерны, средства мониторинга, DI), а те, что не повторялись(Selenium, Selenoid, Specflow), при условии, что человек умеет читать документацию, становятся некритически важными.
Итог
Очевидно, что одними изменениями в автотестах всех целей не добиться. Необходимо менять процессы внутри компании. Мы выделили следующие правила:
- Имплементация новой feature не считается завершенной, если на добавленный функционал не написаны автотесты;
- Нельзя мержить ветку в main branch, если в ней падают тесты;
- "Ever green main branches".
Если данные правила не выполнены, то команда автоматизации будет постоянно находиться в условиях гонки и у команд разработки не будет доверия автотестам.
Описанные подходы внедрены в нескольких проектах компании и успешно функционируют от полугода. Возможно прошедшего времени недостаточно, чтобы делать выводы, но в настоящее время предпосылок менять подход нет.
qwez
Так что в итоге то с автотестерами стало? :)
Всех разогнали и автотесты разработчики пишут? А тест кейсы для конкретной фичи кто формирует?
И еще вопрос: зачем вам Specflow? Без сарказма, реально интересно. Просто во всех случаях, которые встречал, эти ваши кукумберы использовали только потому, что модно.
k_valiev Автор
Вначале в команды автоматизации перестали искать новых кандидатов. Со временем люди либо перешли в разработку, либо ушли из компании. Никого не разгоняли.
В компании каждая команда разработки состоит из 4 DEV и 2 QA. Тест кейсы формитуют QA, так же они формируют сценарий в SpecFlow. Если не хватает реализаций в автотестах внутри команды решают кому это будет сделать проще, чаще всего это DEV.
SpecFlow из коробки предоставляет огромное количество фич, реализация их для framework задача очень трудозатратная. Мы в одном из проектов брали BddFy и доводили его до нужного состояния, на проработку основного функционала потребовалось 2 месяца dev (верхнеуровневая архитектура + DI + converter-ы + читабельный report), а это все еще и поддерживать надо самим.
Или вопрос про BDD подход?
qwez
Ну, т.е. мне кажется проще немного подучить тестеров, чтобы они писали тесты кодом, сделать для них API удобный. Чем поддерживать этот псевдоязычный API.
k_valiev Автор
Уже упомянутый BddFy не имеет Gherkin syntax(псеводоязыка) при этом реализует BDD подход. Gherkin syntax определяет правила описания сценариев, которые совпадают с правилами написания тест кейсов, что позволяет определить однозначное соотвествие между автотестами и набором регрессионных тестов ручных тестировщиков, поэтому его использование это вполне логичный шаг, а не просто модно. BDD подход разделяет сценарии и реализации шагов, что позволяет без дублирования кода из шагов формировать сценарии, что так же является логичным шагом.
Если сомнение именно в псевдоязыке, то есть другие BDD Framework, реализующие правила Gherkin syntax, при этом без псеводоязыка. SpecFlow(cucumber) будет выигрывать за счет возможностей. По крайней мере в мире .Net это так, аналогов SpecFlow по возможностям нет. Для меня killer feature-ами в SpecFlow являются:
1. Встроенный DI контейнер;
2. Встроенная система расширения поведений за счет хуков. Она неявная — это минус, но то, что у меня чистые сценарии, без различных инфраструктурных настроек — это очень удобно;
3. Встроенная система плагинов;
4. У меня с самого начала понятные формулировки степов, поэтому после того, как произошел мапинг результатов во внешнюю систему, я без труда понимаю, что происходило в этом сценарии;
Это дорого. SpecFlow(cucmber) — определенный стандарт, а это значит, что есть множество third-party libraries, что инструмент активно развивается.