Управление тестами в TestOps: храните информацию, а не выводы |
24.06.2021 00:00 |
Автор: Руслан Ахметзянов, Qameta Software Обеспечить представление данных из любой большой системы так, чтобы человек мог спокойно с этими данными работать — задача нетривиальная, но давно решенная. В этой гонке уже давно победило "дерево". Папочные структуры в операционных системах знакомы всем и каждому и исторически простое дерево в UI/UX становится первым решением для упорядочивания и хранения данных. Сегодня поговорим о тестировании, так что в нашем случае объектами хранения будут выступать тест-кейсы. Как их хранят чаще всего? Верно, в папочках! Привычно? Да. Но так ли это решение хорошо и универсально? Вопрос подкрепляется существованием исключений: почта, JIRA-тикеты и много чего другого хранится не в папках. Давайте разбираться, почему. Единое деревоЭтот подход позволяет быстро запуститься на старте и смоделировать структуру для построения базы тестов. Например, организовать хранение тест-кейсов для веб-сервиса по страницам (или по фичам) — каждой странице по папочке для тест-кейсов, даже если самих тестов еще нет. Это удобно — сразу можно понять масштаб работ, а по заполненности папочек можно примерно оценить покрытие. ![]() В итоге получается красивое решение, позволяющее команде тестировщиков спокойно и планомерно, с разделением зон ответственности наполнять дерево тестами. Впрочем, если бы все было просто хорошо, эта статься не появилась бы. Что с ним не так?Представим, что у нас есть замечательный веб-сервис, тесты на него написаны, разложены по папкам (по одной на каждую страницу) и выполняются раз в неделю, все счастливы. Однако, в какой-то момент к руководителю QA приходит менеджер (а они всегда приходят!) и просит рассказать о покрытии тестами микросервисов. Это не то, чтобы большая проблема — просто теперь в дополнение к существующей структуре нужно как-то собрать информацию о тестах из папочек и соотнести ее с микросервисами и сделать соответствующий (новый) отчет. Впрочем, чтобы в следующий раз не заниматься рутиной, старший тестировщик предлагает ввести фиксированные уровни у дерева: так у нас появится возможность иметь данные по командам в нашей структуре данных, а команды намного быстрее будут со своими репозиториями разбираться! Отличное решение, только в следующий раз менеджер просит статистику покрытия по фичам (еще один новый отчет)... Если тестов много, сотни или тысячи, то создание каждого нового среза потребует погружения внутрь всех вложенных ветвей и перераспределения тест-кейсов по новой структуре для анализа. В результате общее дерево со временем разбивается на поддеревья: у каждой команды свое поддерево со своими правилами. При необходимости добавления дополнительного признака в тесты никто не пойдет править чужие поддеревья: неудобно, не надо, процессы уже завязаны на текущую структуру, некогда этим заниматься, "не трогайте наши тесты!" и еще по миллиону причин. В итоге получается картина, когда дерево папок общее, но в каждом поддереве свои уровни.
При росте проекта и требований к прозрачности тестирования возникает второе ограничение папочной структуры: ее очень сложно обслуживать. Продукты редко становятся проще, поэтому со временем наступает момент, когда структура хранения тест-кейсов, созданная на старте, морально устаревает. Со временем обнаружится, что папочки в изначальной структуре расплодились и превратились в неуправляемый ад. Мудрым решением пересобрать структуру по другому критерию, по фичам. Для этого надо спроектировать новую структуру, уже вместе с аналитиком (если такой есть) разобраться с фичами, и аккуратно переносить все тесты в новую структуру. Выглядит несложно, однако такой процесс в крупных проектах занимает недели и месяцы, и если те, кто с таким пока не столкнулся — счастливые люди. ![]() В итоге папочки станут снова управляемыми, уровни вложенности структурируются, но снова получится только один срез — по фичам. Если попытаться создать структуру с двумя срезами, по фичам и компонентам сразу, ее сложность и запутанность создаст больше проблем, чем пользы. А если у вас 3000 тест-кейсов? А если 10000? Впрочем, чтобы столкнуться с ограничениями папочной структуры хранения тестов, не обязательно ждать менеджера с каким-либо "хитрым" запросом. Если в недавно переработанной структуре по фичам понадобится найти самый "красный" компонент, сделать этого скорее всего не получится: вы найдете самую красную "папочку" с фичей, но какие компоненты в ней тестируются, сходу будет не понять. С любой метрикой качества тестирования или продукта придется идти разбираться головой и руками. Еще один подводный камень хранения тестов в папках ждет тех, кто планирует хранить в них автоматизированные тесты, написанные на разных языках программирования. Тут все просто: в Java тесты хранятся по полному имени пакет вроде io.qameta.allure, а в JavaScript или Python — просто по имени пакета. Это значит, что при автоматической генерации тест-кейсов из автотестов, каждый фреймворк будет городить свои подструктуры в дереве и вся нормализация и базовая структура будет нарушена. Конечно, можно написать свою интеграцию для каждого фреймворка, но мы же стараемся упростить себе жизнь, верно? ![]() Самое время задаться вопросом, при чем здесь принятие решений из заголовка статьи. Ответ прост: все перечисленные недостатки связаны с тем, что папочная организация хранения тест-кейсов заставляет команду тестирования с самого начала принимать решение о структуре тестов, а не просто хранить информацию о тестовых сценариях и их результатах. Мало будет просто "подумать наперед" — придется рассчитывать, что будет с проектом и командой тестирования через год-два, а лучше через три. К сожалению, чаще всего прогнозы оказываются неверными: можно переоценить темпы роста и годами сидеть в структуре "на вырост" или, наоборот, недооценить их и оказаться в структуре, неудобной команде и коллегам. Как эту задачу решали Ops'ы?С ограничениями классического дерева разобрались, а как их обходить? На самом деле, с этой задачей уже сталкивались многие, и изобретать велосипед нет необходимости. Большинство систем, работающих с большими объемами данных или большим количеством объектов переходят на плоскую структуру с навигацией по признакам. Самый яркий из недавних примеров — инструменты мониторинга типа Grafana и Graphite. Давайте рассмотрим его повнимательнее и попробуем применить к тестированию. Админы и все те, кто работают в Ops к метрикам и данным относятся с большой щепетильностью и любовью. Просто потому, что о падении сервиса, сети или недоступности какой-то кластера вы захотите узнать раньше пользователя, так? Изначально весь мониторинг строился по классической иерархической структуре: дата-центр → кластер → машинка → метрики (CPU, RAM, storage и прочее). Удобная и понятная система, которая работает, если не приходится в реальном времени отслеживать десяток метрик, которые не привязаны к физическим машинам. А метрики для Ops'ов очень важны. Например, нужно получить срез загрузки всех машин, на которых крутится какой-то микросервис. Построить такой срез при единой иерархической структуре — задача нетривиальная. Задачу решили понятным и элегантным способом: сложили все объекты в единый пул и начали каждый помечать необходимыми метками-признаками. Набор меток хранится в плоской структуре и свободно используется — любой критерий поиска, фильтрации или группировки становится меткой: метрика, статус, география, сервис или компонент, положение в иерархии или отношение к команде. Такой подход позволяет освободить систему хранения от навязывания решений о структуре и хранить размеченные данные и метаданные так, чтобы иметь к ним доступ без "лишней" нагрузки.
Чтобы получить отчет или анализ данных, нужно просто указать, по каким критериям срезы нас интересуют: нагрузка на CPU по инстанстам, разделенным по географии. Такой метод управления данными позволяет не только фильтровать и делать выборки внутри структуры. Он предоставляет еще один уровень свободы в виде вышеупомянутой группировки: теперь можно спокойно сделать запрос к хранилищу вида "покажи статистику доступности всех машин, на которых крутится такой-то микросервис с группировкой по кластерам". Парсер проходится по всем машинам, забирает статистику доступности с тех, на которых стоит метка микросервиса и группирует их по кластерам. При этом следующим запросом можно спокойно получить "загруженность кластеров по географии" — дерево перебалансируется, перенеся кластеры на нижний уровень, а географию на первый. В любой момент по запросу пользователю доступна любая аналитика и любой срез данных. Зайдите в дэшборды любой Ops-команды крупного сервиса, — здесь найдутся отчеты по десятку метрик (uptime, загрузка ресурсов, количество пользователей и т.д.), нарезанных по множеству критериев (география, балансировка между серверами и пр.). — Да это же просто автоматизация папочек! — скажете вы. И это прекрасно — это классическое решение проблемы масштабирования. Конечно, у системы с метками есть несколько минусы:
Тест-кейсы: дерево против меток— Хорошо, с админами все понятно. Они там сидят и целый день смотрят в метрики и крутят данные. А нам-то зачем? Ответ прост: мир разработки, к сожалению или к счастью, уже давно ушел от жесткой структуры — релизы ускоряются, сборки автоматизируются. На фоне этих изменений, мир тестирования в большинстве компаний выглядит немного архаично: на новые фичи готовится по пачке новых тест-кейсов для ручных тестов и автоматизации, они раскладываются по папкам, запускается в тестирование на неопределенный срок (от 1-2 дней до недели), собирается результат тестирования и отгружается обратно в разработку после полного завершения. Ничего не напоминает? Это же старая добрая каскадная разработка (waterfall, то бишь)! В 2021 году. Если послушать Баруха Садогурского в одном из подкастов, где он довольно убедительно рассказывает, что любой процесс — это по сути agile, в котором "мы пытаемся отложить принятие решения максимально далеко, чтобы перед этим собрать побольше данных", станет понятно, почему весь мир разработки гонится за короткими итерациями и быстрыми релизами. Именно поэтому разработчики уже давно пишут софт итеративно, внедряя по одной фиче или паре фиксов на релиз, опсы отгружают эти релизы как можно скорее, которые перед этим тестируются. А как они тестируются? Скорость разработки и развертывания требует от тестирования скорости в предоставлении результатов — больше нет времени на полуавтоматический анализ из статичного дерева, — вашим коллегам нужно много данных с разных срезов. А если вы затрудняетесь их готовить, то действительно ли тестирование приносит максимальную пользу? Посмотрите на последние веяния в тестировании для DevOps заключаются в том, чтобы тестировать как можно меньше и как можно быстрее: это приводит к подходам вроде shift right и тестируйте как можно меньше. Практики, направленные на скорость, повторяемость и стабильность выполнения тестов, а не покрытие и оценку качества в широком смысле — про это в свое время буду писать отдельные статьи. Поэтому, чтобы оставаться в мире, где тестирование отвечает за качество продукта, давайте вернемся к нашим папочкам и признакам. Создавая папочную структуру, мы изначально закладываем в хранилище тест-кейсов принятое решение о том, в каком виде хотим получать отчеты и видеть результаты. Проблема в том, что мы не знаем какие отчёты понадобятся в будущем.
В конце концов, никто не захочет разбираться с закостенелой структурой, которая удобна для отдела контроля качества. Чтобы тесты были полезны, их результаты должны быть гибкими и максимально атомарными, готовыми для сборки произвольных отчетов. Поэтому давайте собирать метаданные, а потом разбираться. По ним можно будет строить отображение дерева тестов в нужном виде: для тестировщиков — по фичам, для разработчиков — по классам, или вообще списком с сортировкой по имени: ![]() Тестирование так же, как и мониторинг из примера, работает с метриками. Их может быть много или очень много, и придумать универсальную и вечную структуру просто невозможно. А собрать и сформулировать исчерпывающий набор метрик и критериев — можно. По сути, вместо одного статичного дерева, управление через признаки позволяет простым и понятным способом сделать генератор деревьев, основанный на нужных критериях, расширяемый и масштабируемый без лишних танцев с бубном. А как только мы получаем автоматически генерируемые выборки и группы, мы можем настроить автоматический live-репортинг и генерацию отчетов. Самый понятный пример — JIRA, где можно по любому полю тикета построить график, тренд или дэшборд любого вида, собрать, отфильтровать или сгруппировать тикеты (могут понадобиться плагины!:)) в любую структуру прямо на митинге. Согласитесь, звучит заманчиво: иметь гибкость JIRA-тикетов в управлении тест-кейсами. Останется только автоматизировать запуски на слияние веток и вот тестирование уже отвечает требованиям DevOps! ![]() |