Pull to refresh
18.68

Нам требовался мониторинг покрытия проекта автотестами. Для этого мы разработали сервис Coverage Manager

Reading time8 min
Views2.2K

Summary: Игорь Зубцов, руководитель автоматизированного тестирования в направлении омниканальных решений Лиги Цифровой Экономики, рассказал, как его команда разработала сервис для мониторинга покрытия автоматизированными сценариями, с какими сложностями столкнулась и как он работает.

В этой статье я бы хотел рассказать о разработанном нашей командой сервисе Coverage Manager. Мы используем его для мониторинга покрытия автоматизированными сценариями, однако разработку можно применять и на других проектах.

Естественное желание — видеть наглядный результат работы автоматизаторов на проекте. Всегда хочется знать, а главное, видеть ответы на вопросы: «А что у нас с покрытием этого функционала?», «А покрыт ли у нас этот сценарий?» и подобные. Coverage Manager предназначен для визуальных ответов на многие такие вопросы. Любой причастный к проекту человек может зайти и посмотреть, покрыт ли тот или иной сценарий автотестами, а также пронаблюдать динамику.

***

Когда проект только начинался, у нас работали один автоматизатор и несколько ручных тестировщиков, острой необходимости в снятии метрик автотестирования на тот момент не было. Но постепенно команда росла, проект с монолитной архитектурой оброс микросервисами, и становилось все сложнее помнить и понимать, какой функционал покрыт тестами. Первоочередной целью мы выбрали подсчитать покрытие функционала API-тестами.

Это было особенно важно, поскольку команда проекта поделилась на стримы, и автотестировщики работали относительно изолированно, внутри своих небольших команд, — а из-за этого тесты могли пересекаться.

Мы проанализировали рынок, однако на тот момент подходящих нашей команде инструментов для сбора статистики не существовало.

API-покрытие. Версия 1

Прежде чем перейти к рассказу о Coverage Manager, хотелось бы уточнить, на каком стеке технологий мы в принципе разрабатываем наши автотесты, так как далее рассмотрим варианты автоматизированных сценариев. Речь сегодня пойдет в основном про автотесты API, поэтому рассказывать буду на примере именно таких сценариев.

Для написания автоматизированных проверок API мы используем так называемый «Огурец» Cucumber и java-библиотеку Rest Assured, которая позволяет отправлять rest-запросы на сервер, получать ответы, извлекать из них все необходимые данные (тело ответа, заголовки, куки и т. д.).

В cucumber для написания тестов используется gherkin-нотация. Так выглядит простой сценарий:

@getTestMethodOne
Функционал: Проверка вызовов тестовых методов

  @test
  Сценарий: Вызов первого тестового метода GET
    Пусть пользователь планирует вызывать метод "/api/test/method/one"
    И пользователь делает GET вызов
    Тогда пользователь получает ответ с кодом "200"

В коде основного проекта разработчики помечают методы и классы аннотациями, из которых потом генерируется swagger. В этой документации есть уникальный для каждого API параметр operationId.

"/test/method/one": {
    "get": {
        "tags": [
            "test"
        ],
        "summary": "Первый тестовый метод GET",
        "description": "Описание первого тестового метода GET",
        "operationId": "getTestMethodOne",
        "produces": [],
        "parameters": []
    }
}

В первой версии Coverage Manager мы решили считать покрытие API, используя эти параметры за основу. То есть сценарию, в котором вызывается тот или иной API, проставляли тег с этим самым operationId и как бы мапили этот сценарий с тем, что у нас есть в swagger проекта.

После того как мы присвоили такие теги всем нашим автоматизированным сценариям, мы написали небольшой обработчик. Во время прохождения тестов он находил все подобные теги и затем записывал их в отдельный файл. Последний отправлялся в Coverage Manager, там обрабатывался, после чего отображались результаты покрытия.

В этой версии у нас был только фронт, написанный на react, то есть логика обработки файла с массивом тегов operationId и сам swagger проекта производились прямо на фронте.

Быстро стало очевидно, что подобный подход к подсчету покрытия не отображает реальных показателей. Представим: для метода есть пять сценариев, которые необходимо проверять тестами, а мы смотрим только один. В таком случае API по этому подходу будет считаться покрытым.

Хотелось решить эту проблему наравне с некоторыми другими. Но также была и другая сложность: помимо монолитной части бэкенда, на проекте стали появляться микросервисы. И покрытие API микросервисов в этом варианте никак не учитывалось.

Мы начали думать о том, как можем приблизиться к решению этих двух проблем.

API-покрытие. Версия 2

После реализации первой версии менеджера по покрытию состоялась конференция Heisenbug, где был представлен доклад Артема Ерошенко из Qameta Software.

Это выступление и легло в основу написанного нами алгоритма по подсчету покрытия.

Построено все на формировании и сравнении swagger-документации. Так, swagger — это документация, которая генерируется по конкретному сервису и содержит список запросов, их параметры и коды ответов. Удобно, что не нужно каждый раз вносить данные вручную или получать информацию от других людей: генерация происходит автоматически.

Так как мы могли получать такой сгенерированный файл со спецификацией по всем методам проекта, то реализовали генерацию спецификации API внутри фреймворка автотестов, а именно — java-библиотека swagger через фильтр встраивается в отправляемый запрос и позволяет получить всю необходимую информацию для описания API.

С помощью этого фильтра можно инспектировать и изменять запросы и ответы до их завершения. Функционал — это лишний шаг на этапе вызова метода в автотесте, где информация перехватывается, анализируется и обрабатывается. Таким образом, после прохождения автотестов мы получаем не просто набор тегов, как было в первой версии сервиса, а полноценный swagger.json-файл, построенный на основе наших автотестов.

Пример фильтра:

import behavior.action.swagger.SwaggerCoverage;
import io.restassured.filter.Filter;
import io.restassured.filter.FilterContext;
import io.restassured.response.Response;
import io.restassured.specification.FilterableRequestSpecification;
import io.restassured.specification.FilterableResponseSpecification;

public class RestAssuredFilter implements Filter {
    @Override
    public Response filter(FilterableRequestSpecification requestSpec,
                           FilterableResponseSpecification responseSpec,
                           FilterContext ctx) {
        final Response response = ctx.next(requestSpec, responseSpec);

        (new SwaggerCoverage()).addItem(requestSpec, response).save();

        return response;
    }
}

Ежедневно файл с данными по автотестам мапится со swagger-файлами сервисов, и результаты записываются в базу MongoDB. Последние обновляются автоматически по настроенному расписанию через сервер Jenkins.

Единицы подсчета

Перед дальнейшим описанием работы алгоритма Coverage Manager необходимо уточнить несколько понятий, используемых в контексте нашего сервиса: это такие единицы измерения, как фича и сценарий.

Фича представляет собой отдельно взятый API вместе с http-методом (таким как GET, POST и т. д.), и дальше дробится на сценарии.

Сценарий же, в свою очередь, состоит из уникального сочетания пути метода и кода ответа (например, 200, 400 и т. д.).

 Пример сценария:

@test
Сценарий: Вызов первого тестового метода GET
  Пусть пользователь планирует вызывать метод "/api/test/method/one"
  И пользователь делает GET вызов
  Тогда пользователь получает ответ с кодом "200"
	

На указанном примере представлен отдельный сценарий (путь запроса, http-метод и код ответа). Совокупность таковых с одинаковыми путями и http-методами мы и считаем фичей. Например, аналогичный автотест с ожидаемым кодом ответа 400 будет уже вторым сценарием в рамках одной фичи.

А если существует точно такой же автотест, но вместо GET-запроса будет отправляться DELETE-запрос, то это уже будет считаться отдельной фичей.

Визуализация

После перехода на новый алгоритм подсчета покрытия объем обрабатываемой информации значительно увеличился. Было решено, что пришло время отказаться от обработки всей информации только на стороне фронта. Поэтому мы добавили в наш сервис бэкенд-модуль, написанный на express, а также mongo-базу, чтобы каждый раз не приходилось заново обрабатывать входной файл swagger автотестов, swagger проекта, а также спецификации всех микросервисов проекта.

Все эти обработанные данные при первом вызове нашей API записываются в базу, и в дальнейшем основная работа ведется именно с базой данных.

Расскажу немного подробнее, как это работает. Мы уже упоминали о ежедневном обновлении данных: оно выполняется с помощью вызова API Coverage Manager, в теле запроса которого передается swagger.json из репозитория автотестов. Внутри API также происходит получение swagger монолитной части и openapi-спецификаций всех микросервисов проекта. После этого в базу записываются новые фичи, если такие есть. Например, когда в swagger проекта появился новый API.

В ином случае изменяются уже существующие записи, например, когда сценарием был покрыт какой-то новый код ответа. Возможен и вариант удаления фичи из базы, скажем, если метода больше нет в swagger.

Здесь мы столкнулись с небольшой проблемой актуализации данных в файле swagger.json автотестов: удаление какого-либо сценария из репозитория автотестов возможно только через ручное редактирование файла. Пока что решение для автоматизации этого кейса не нашли.

Основной экран мониторинга Cover Manager:

На изображении выше — основная страница сервиса с графическим отображением информации о покрытии и сценариях.

Слева — график статистики прироста новых сценариев, которая разбита на стримы. (Деление на стримы в нашем случае — это дробление общего продукта на отдельные зоны, связанные между собой функционально. Например, личный кабинет, магазин и т. п.) Справа отображается общая цифра покрытия тестами по проекту в процентах и учет количества покрытых или непокрытых сценариев.

Основная часть экрана отведена под вывод фич и фильтра. С помощью фильтра можно посмотреть непокрытые сценарии определенного стрима. Каждая фича отображается с детализацией по коду ответа, то есть наглядно видно, какие сценарии той или иной фичи учтены в автотестах, а какие нет.

На отдельных страницах мы выводим статистику покрытия отдельно взятой команды.

Принадлежность фичи тому или иному стриму определяется во время обработки swagger-файла автотестов перед записью в базу данных. Маркеры стримов — теги автотестов, которым заполняется массив tags.

"/api/test/method/one": {
    "get": {
        "tags": [
            "Команда 3",
            "Команда 5"
        ],
        "parameters": [],
        "responses": {
            "200": {
                "description": ""
            },
            "400": {
                "description": ""
            },
            "404": {
                "description": ""
            },
            "503": {
                "description": ""
            }
        }
    }
}



Если тегов несколько, то в данные будет записан по умолчанию первый. Но есть возможность изменить значение этого параметра вручную через веб-интерфейс.

Доступ к этой вкладке есть у каждого члена команды. Это может быть удобно для планирования целей покрытия и понимания прогресса работы команды автотестирования. На нашем проекте каждый стрим закреплен за определенным автоматизатором, для которого он в основном и пишет автотесты. Этот раздел можно использовать как один из критериев оценки работы (если нужно выставить какие-либо личные цели по покрытию).

Аналогичный вывод информации доступен для каждого отдельно взятого сервиса.

Это может быть актуально для проектов с микросервисной архитектурой. Информация полезна как для автоматизатора, который после завершения всех текущих задач может увидеть статистику непокрытых микросервисов и взять в работу задачу по написанию автотестов для них, так и для любого члена команды. Например, мануального тестировщика, который сможет составить более оптимальный план регрессионного тестирования.

***

Мы понимаем, что нынешний алгоритм подсчета покрытия все еще не эталонный и не отражает полной картины. Хотя по сравнению с нашей первой версией мы получаем более точные данные, все еще есть куда стремиться. Поэтому в дальнейшем мы планируем дорабатывать сервис.

Один из главных векторов развития для нас — детализация текущего покрытия API. А именно — дробление сценариев с учетом проверок query-параметров, заголовков и т. д.

Кроме того, уже разрабатывается функционал мониторинга покрытия веб-тестами. Мы планируем отображать статистику для таких сценариев аналогично в процентах и фичах, но в основе деления на сценарии будет лежать дерево функционала, где каждая конечная ветвь и будет конкретным сценарием.

Еще один важный для нашей команды функционал — добавление истории покрытия. Мы собираемся научить сервис фильтровать сценарии с учетом периода их добавления. Это может быть полезно при составлении статистики. Например, сколько сценариев было покрыто за текущий месяц, за предыдущий и т. д. В перспективе история изменения покрытия сможет показать, насколько эффективно (или наоборот) команда работает от месяца к месяцу.

Tags:
Hubs:
Total votes 3: ↑2 and ↓1+3
Comments2

Articles

Information

Website
digitalleague.ru
Registered
Employees
5,001–10,000 employees
Location
Россия