Разработчики и тестировщики заводят тест-кейсы в систему хранения тестов (TMS), но это долго и никому из них не нравится. При этом QA-инженеру нужно как-то отслеживать и подсчитывать для пирамиды тестирования unit-тесты, которые написаны в коде приложения. Решить эти задачи может одна система — кастомная TMS, она умеет выгружать все тесты из кода и визуализировать тестовое покрытие в понятные графики и числа.
Меня зовут Василий Юдин, я инженер в Авито и техлид команды, которая разрабатывает инструменты для тестирования. Рассказываю, как мы с командой создали хранилище тестов с выгрузкой из кода и как оно помогло нам в работе.
Почему мы решили делать свою TMS и сервис выгрузки тестов из кода
Раньше в Авито были отдельные команды разработки и QA. Тестировщики приходили на конкретные задачи и помогали разработчикам с тестами.
Со временем компания выросла, мы начали применять Scrum, а QA-инженеры стали постоянными членами Dev-команды. При этом в начале спринта, когда работа над задачами только начиналась, тестировщикам было нечем заняться. Но к концу второй недели разработчики разом отдавали все фичи на тестирование, и QA оказывался в огне. Качество тестов падало, а человек постепенно выгорал.
Проблему решило Agile-тестирование. Это практика, которая основана на одном из постулатов Scrum: за качество продукта отвечает вся команда. При таком подходе разработчики пишут unit-тесты в коде приложения. А тестировщик на этапе планирования подсвечивает кейсы, которые нужно протестировать, разрабатывает критерии приёмки и принимает тесты на код-ревью.
Всё работало хорошо, но Авито продолжал расти. Знаний о качестве продукта становилось больше. QA-инженерам стало сложно держать в голове всю необходимую информацию о тестах. Качество продукта перестало быть прозрачным: приходилось собирать информацию отдельно от каждой команды. К тому же когда приходил новый сотрудник, его сложно было погрузить в работу, потому что данные о тестировании были у разных людей. Проблему мы решили тем, что внедрили TMS.
Как выглядит тестовая модель и карточка тест-кейса в TMS Авито
Выгружать все тесты в кучу бесполезно: будет хаос и прозрачность качества не повысится. Мы решили сразу привязать все данные к тестовой модели и выбрали для неё древовидную структуру, как самую простую для понимания. Верхний уровень — более абстрактные понятия и фичи; чем ниже, тем более простые и понятные элементы. Каждый нижний уровень относится к конкретной фиче, например странице заказа или справке. Уровни называются нодами.
В карточке тест-кейса прописывается всё, что нам нужно и важно отслеживать: название, приоритет, тип теста и принадлежность конкретной команде. Затем указывается ID ноды, к которой относится тест. Есть поля для описания тестового сценария и тестовой модели.
С TMS стало удобнее хранить и отслеживать тесты, но карточки для них создавались вручную. Мы не хотели нагружать разработчиков двойной работой: сначала написать тест в коде, затем сходить в хранилище тестов и сделать карточку. QA-инженерам на код-ревью нужно контролировать, что именно разработчики пишут в тестах и что они занесли в карточки тест-кейсов. Поэтому решили, что нужно автоматически выгружать тест-кейсы из кода прямо в TMS.
Мы поискали готовые решения — их было несколько, но они нам не подошли. Для выгрузки важно было учесть ещё одну особенность Авито: в командах всегда использовали много разных языков и тестовых фреймворков. Поэтому пришлось делать собственный сервис выгрузки, который мог работать в таких условиях.
Как можно выгружать тесты из кода TMS
Мы исследовали разные подходы к выгрузке тестов и разделили их на две группы: первым для работы нужно прогнать сами тесты, вторым это не требуется.
Вы можете получить данные о тестах и их результатах, если запустите проект, например, в TeamCity. В отчёте о прогоне, как минимум, можно увидеть простые бинарные состояния: пройден тест успешно или нет. Но в этот же отчёт можно добавить дополнительную информацию: указывать приоритет, тестовую модель или вид теста.
У выгрузки с прогоном тестов есть два значительных минуса:
чтобы вносить в отчёт новые данные, вероятно, придётся доработать тестовый фреймворк, например использовать хендлеры и ивенты;
прогон, особенно для регрессионных тестов, может занимать несколько часов — это не всегда удобно.
Выгрузку тестов без запуска кода мы разделили на три вида:
1. Рефлексия
Для многих языков разработки есть пакет для дебага приложения. Обычно в них есть библиотека reflection, которая позволяет достать нужные данные: прочитать аннотации к тест-кейсам, узнать дата-провайдера, выгрузить dataset. Например, такая библиотека есть для PHP, с ней удобно работать.
Но тут есть подводные камни. Допустим, чтобы получить dataset на JS, требуется запустить код проекта, в котором он используется. Для этого нужно подключить зависимости, поднять контейнер в Docker — работы становится больше, чем если заполнять тест-кейс в TMS вручную.
2. Регулярные выражения
Довольно простой способ выгрузки. Достаточно сделать git clone проекта и написать несколько строк кода. Метод подходит для любого языка и тестового фреймворка, не требует зависимостей.
Но есть проблема: в компании должен быть единый код-стайл. Если каждый разработчик пишет код по-своему, невозможно сделать общее регулярное выражение, которое будет корректно выгружать все варианты. Можно попробовать написать несколько регулярных выражений. Но непонятно, какому из них верить, если первое показывает три тест-кейса, второе — четыре, а третье — десять.
3. Парсинг на ast-ноды
Практически любой код перед запуском проходит через синтаксический анализатор, он разбивает текст программы на ast-дерево. Например, в строке есть слово, которое определяет функцию, а следующие три слова — это аргументы. В итоге мы получаем ряд ast-нод, затем можем перевести их в байт-код и выполнить всю строку изначального кода.
Такой же подход можно использовать для выгрузки тест-кейсов: разбить файл с кодом на ast-ноды, просмотреть дерево и выбрать те ветки, которые относятся к тест-кейсам. Затем перевести их, например, в JSON и перенести в TMS.
Когда моя команда работала над сервисом выгрузки, мы не могли использовать ast-ноды из-за большого числа языков в компании. Поэтому выбрали регулярные выражения как универсальный метод.
Как мы выгружаем тест-кейсы из кода с помощью регулярных выражений
Сейчас мы используем для парсинга тест-кейсов регулярные выражения, которые могут выгрузить 48 разных видов тестов.
При этом сами тест-кейсы нужно размечать достаточно подробно, чтобы собрать все нужные данные. У нас есть несколько обязательных полей:
tag_id — ID ноды тестовой модели;
title — название теста;
testType — тип теста;
priority — приоритет.
И ещё около 10 необязательных полей, таких как description, feature_id и precondition.
Если размечать тест всеми этими полями, получится очень подробная и объёмная разметка. Это наглядно, но неудобно для разработчиков.
Поэтому всю повторяющуюся разметку мы вынесли в отдельный конфигурационный файл.
После этого стало гораздо лучше: минимальная разметка занимает всего одну строку. Разработчику достаточно указать tag_id и title для теста.
Внешний вид карточки в TMS практически не зависит от того, создана она вручную или выгружена из кода приложения. Отличий только два: у автоматически созданных карточек есть тег «откуда/выгружен/тест» и external ID, которые присваиваются системой.
Что умеет делать TMS в Авито
Сейчас TMS и сервис выгрузки тест-кейсов из кода в Авито разделены. Также у нас есть отдельный сервис Event Gateway, который собирает ивенты от Git. Все сервисы взаимодействуют по API.
Когда разработчик закоммитил новую функциональность и слил ветку в мастер, Git отправляет событие в Event Gateway — он создаёт сообщение в шине данных Kafka. Сервис выгрузки тестов получает сообщение от Kafka, делает Git clone новой версии мастер-ветки, парсит тесты и по API загружает тест-кейсы в TMS.
В Авито есть много разных сервисов, которым нужна информация об изменениях в коде. Поэтому потребовалась сложная схема взаимодействия через отдельный Event Gateway. Если у вас не такая крупная компания, достаточно подписать сервис выгрузки на события Git напрямую.
Когда все тест-кейсы загружены в TMS, мы можем строить аналитику: дерево тестовой модели окрашивается в разные цвета. Для каждой ноды указывается общее число кейсов. Строится пирамида тестирования, которую можно посмотреть по клику на ноду.
В TMS можно отслеживать некоторые метрики, важные для оценки качества продукта. Например, процент автоматизированных тестов по каждой команде.
В TMS можно посмотреть, сколько тест-кейсов из кода загружено в каждый рабочий день. Например, если выкатили новую фичу, то должны появиться новые тест-кейсы. Если их нет, значит, что-то пошло не так и функциональность не протестирована полностью.
Ещё один график нужен больше для моей команды. Мы отслеживаем общее количество тест-кейсов, чтобы планировать развитие TMS. И главное — можно покрыть метриками качество всего продукта. На них мы опираемся, когда разрабатываем технические проекты по улучшению Авито.
Что даёт использование TMS
Какие итоги можно подвести:
Регулярные выражения нужно использовать осторожно. Будьте готовы, что к вам в поддержку будут приходить люди, которые не понимают, почему их тесты не выгружаются. Особенно если используется много разных языков разработки, нет единого код-стайла.
Но на старте, когда вы хотите проверить гипотезу и получить 80% результата за 20% работы, — это отличное решение. Также регулярные выражения хорошо подойдут, если вы используете один-два языка и обязательный код-стайл.
Абсолютно всё нужно логировать. Если по какой-то причине автоматическая выгрузка тест-кейса из кода не прошла, вы сможете в логах узнать причину или хотя бы точку, откуда начинать поиск.
TMS повышает инженерную культуру разработчиков. Меняется подход к архитектуре приложения: разработчику нужно соблюдать пирамиду тестирования, покрывать код unit-тестами. Например, сразу хочется избегать многоуровневого наследования, использовать инверсию зависимости, выносить повторяющиеся конфигурации из кода. Это в целом хорошо влияет на качество продукта.
Следить за качеством тестирования становится проще. Например, можно заметить, когда не хватает автоматических тестов, и поставить ответственной команде задачу на ближайший квартал.
Легко онбордить новичков: тестовая модель отображает функциональность приложения, как её тестировать и где она находится в коде.
Предыдущая статья: Как мы научили тексты в вебе жить по правилам