В прошлом году нашей QA-команде нужно было интегрировать Allure TestOps в проекты. До этого никто из нас этим не занимался, но вместе разобрались и сделали. Я осознал, что в одиночку потратил бы на это очень много времени или вообще бы не разобрался, потому что инструкции, как это сделать, не было. Поэтому написал свою, в надежде, что она будет полезна тем, кто окажется в такой же ситуации.

В общем, если вы тестируете бэкенд на .NET, а для сборки проектов используете GitHub Actions и хотите внедрить Allure TestOps — эта инструкция для вас.

Allure TestOps — это Test Management System (TMS), которая изначально строилась с фокусом на автоматизацию и подход «тест-кейсы как код». Конечно же, это не случайно, т.к большинство автоматизаторов используют Allure Report и в коде автотестов уже используются механизмы разметки отчётов — эти же механизмы используются и для интеграции с Allure TestOps.

Недавно мы закончили интеграцию c Allure TestOps, и я решил написать инструкцию, как быстро и легко затащить к себе этот инструмент, если вы раньше никогда такого не делали.

Из чего состоит Allure TestOps

Для начала давайте посмотрим, что внутри.

  • Allurectl — это CLI-интрефейс-обёртка над API Allure TestOps, которая умеет управлять тест-кейсами, лончами и другими сущностями и загружать результаты тестов в TestOps.

  • Allure Report — бесплатный инструмент, который формирует и визуализирует отчёты по прогонам автотестов. Существуют реализации для большинства языков и тестовых фреймоврков. Мы используем реализации для C#, JS, Kotlin и Swift.

  • Allure TestOps — платный инструмент, который использует механизмы формирования отчётов Allure Report для интеграции между тестами и самой TMS. По ним формируются тест-кейсы, статистика и т.д. Во главу угла ставит подход «тест-кейсы как код».

Для чего внедрять Allure TestOps

Allure TestOps стоит внедрять, если мы хотим:

  • иметь единое место для всех отчётов о прогоне. Например, наши микросервисы собирались в GitHub Actions (GHA), а монолит — в TeamCity. Это уже было проблемой, потому что результаты прогонов тестов были в разных местах. Нужно было собрать информацию о запусках тестов в одном месте. А так же хотелось легко видеть причину падения, success rate тестов и тесты, упавшие по одной причине;

  • перестать писать ручные тест-кейсы или сократить их написание до минимума;

  • избавиться от ручной поддержки тест-кейсов;

  • чтобы метрики собирались автоматически. Например, нам нужны были метрики success rate тестов и длительность прохождения теста, и в GHA их не было.

Наш стек

Я тестирую преимущественно бэкэнд, написанный на .NET, поэтому примеры будут на .NET + NUnit + Speclow. Для сборки проектов мы используем GHA.

Общие шаги

Давайте верхнеуровнево рассмотрим шаги, которые нужны для интеграции Allure TestOps с автотестами.

  1. Получить пробную версию Allure TestOps.

  2. Выполнить первичную настройку проекта в Allure TestOps.

  3. Подключить к проекту с тестами зависимости на Allure Report.

  4. Разметить автотесты атрибутами.

  5. Настроить директорию для хранения allure-result.

  6. Добавить в CI шаги по работе с allure-results.

  7. Запустить тесты, дождаться их прохождения.

Получаем пробную версию Allure TestOps

Выбираем self-hosted или cloud-версию, запрашиваем доступы к пробной версии (обычно их дают на месяц). Всё, что мы сделаем в пробной версии, сохранится при покупке полной версии, и мы продолжим использовать уже настроенные проекты и интеграции.

Выполняем первичную настройку проекта в Allure TestOps

  1. Создаём проект. В Allure TestOps это продукт или сервис, на который мы написали автотесты, лежащие в конкретном репозитории.

  2. Настраиваем правила генерации тест-кейсов. Мы оставили генерацию через 24 часа и только из лончей с тегом master (tag is master). Тегом master помечены lounches из мастер-ветки. Все тесты, запущенные на мастер-ветке, будут генерироваться в тест- кейсы. Вы можете указать свою основную ветку.

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

  3. Если хотим, чтобы тесты помечались слоями, например system (за это отвечает атрибут [AllureLabel(”layer”, “system”)]) — добавляем это в настройки.

  4. Настраиваем свой способ построения дерева тест-кейсов. Мы используем такой: Suite1 (атрибут ParentSuite) → Suite2 (атрибут subSuite) → Suite3 (у нас нет третьего уровня, но в настройке указали сразу, вдруг появится).

  5. Настраиваем связку атрибутов из автотестов с кастомными полями. Мы сделали связку атрибута ParentSuite в Suite1 и subSuite в Suite2.

Подключаем к проекту с тестами зависимости на Allure Report

Устанавливаем нужные Nuget-пакеты. Для чистого nUnit — Allure.NUnit, а для SpecFlow — Allure.Specflow.

Если вы используете «маки», вас ждёт прикол: Allures зависят от пакета AspectInjector, и если вы не установите этот пакет явно, то проект перестанет собираться локально.

Размечаем тесты атрибутами

Nunit

Самое важное для NUnit — проставить атрибут [AllureNUnit] в каждом тестовом классе. Без этого Allure не поймёт, что ему нужно взять этот тест и сделать из него allure-results.

SpecFlow

Для Specflow ничего размечать не нужно, он сразу увидит автотесты, шаги в них и сгенерирует результаты.

А дальше всё зависит от наших потребностей. Мы разметили сьюты, чтобы группировать тесты. В своём проекте я разметил ещё и слои тестов, но профита от этого не получил.

Настраиваем директорию для хранения allure-result

Чтобы настроить пути к allure results, нужно добавить в корень проекта с автотестами файл allureConfig.json и указать там путь к директории с результатами запуска тестов. Если этого не сделать, то по умолчанию результаты будут генерироваться в директории путь_до_проекта_с_тестами/bin/Release/net6.0/allure-result (в зависимости от конфигурации запуска тестов вместо Release может быть Debug. В одном проекте я обнаружил, что тесты запускались с конфигурацией Debug, поэтому адрес был bin/Debug/net6.0/allure-result ). Мы обычно просто в конфиге указываем что-то подобное:

{
  "allure": {
    "directory": "../../allure-results"
  }
}

При такой конфигурации директория allure-result создастся в директории bin и путь до результатов будет, например, bin/allure-result.

Обязательно нужно указать, чтобы файл allureConfig.json копировался при сборке проекта. Делается это с помощью нажатия правой кнопкой мыши на файл — Properties — Copy to output directory — Установить параметр Copy always. Если этого не сделать, то allure results будут складываться в директорию по умолчанию.

Добавляем в CI шаги по работе с allure-results

Мы используем в качестве CI GitHubActions, поэтому примеры актуальны для него.

В первую очередь необходимо добавить в GitHub секреты, которые нам отправили при покупке Allure TestOps.

Отредактируем наш workflow билд. Это .yml-файл, который лежит в repository_name/.github/workflows/ .

Что нужно обязательно там сделать:

  • установить переменные окружений из секретов. Можно установить их в глобальных переменных или в переменных конкретного шага — запуска тестов.

    • ALLURE_LAUNCH_TAGS — тег запуска тестов, будет нужен дальше,

    • ALLURE_LAUNCH_NAME — имя запуска тестов, будет нужен дальше;

  • подготовить allurectl к работе, указав id проекта, версию allurectl. Мы используем официальное решение https://github.com/marketplace/actions/setup-allure-testops.

    • ALLURE_ENDPOINT — эндпоинт возьмётся из секретов.

    • ALLURE_TOKEN — токен возьмётся из секретов.

    У нас шаг выглядит так:

    - name: Setup Allure TestOps
            uses: allure-framework/setup-allurectl@v1.0.0
            with:
              allure-endpoint: ${{ secrets.ALLURE_ENDPOINT }} 
              allure-token: ${{ secrets.ALLURE_TOKEN }} 
              allure-project-id: 3
              allurectl-version: 1.23.0

    Версию лучше указывать явно. При обновлении что-то может сломаться и мы сразу получим неработающую сборку. У нас возникла проблема: на релизе 2.0+ версии allurectl перестала формироваться ссылка на запуск. Если бы мы не указали версию, в один момент у нас бы сломались ссылки на запуски во всех проектах;

  • залить результаты в allure storage . На этом шаге остановимся подробнее. Есть 2 варианта загрузки результатов:

    • с помощью allurectl watch. Эта команда оборачивает dotnet test и выполняется вместе с ней. Результаты в реальном времени подгружаются в облако;

    - name: Run backend component tests
            id: component-tests
            run: allurectl watch --results src/Dodo.Tracker.ComponentTests/bin/allure-results -- dotnet test --no-build src/Dodo.Tracker.ComponentTests

    • с помощью allurectl upload. Upload — это отдельный шаг в скрипте, в котором нужно указать путь до результатов.

      Указывать необходимо путь до папки с результатами, например, bin/allure-result Вот тут я делал неправильно и использовал путь bin/ с уверенностью в том, что allurectl upload найдёт папку allure-result и загрузит оттуда все данные. Это не так. Он загрузит в облако всё, что найдёт в директории bin/ (dll-ки, результаты тестов, exe-файлы). В облаке уже происходит фильтрация, остаётся только то, что нужно, ненужное удаляется. Но с таким подходом увеличивается время загрузки, что в свою очередь увеличивает время прохождения тестов. А мы этого не хотим.

      - name: Upload allure results
              if: ${{ always() && steps.run-backend-component-tests.outcome != 'skipped' }}
              run: allurectl upload --launch-name "${{ env.ALLURE_LAUNCH_NAME }}" --launch-tags "${{ env.ALLURE_LAUNCH_TAGS }}" src/Dodo.Tracker.ComponentTests/bin/allure-results

      Если выбирать из двух вариантов, то watch не такой гибкий. Если все тесты проходят, но по какой-то причине упадёт загрузка результатов (например, из-за проблем в Allure), то при использовании watch наш билд упадёт. Но упавший Allure — это не повод фейлить билд. Поэтому upload в этом отношении гибче, он выполняется как отдельный шаг и все остальные шаги можно продолжить выполнять, даже если шаг с загрузкой результатов не выполнился. Но upload увеличивает время прохождения тестов и всего пайплайна. Чем больше тестов, тем больше результатов ,тем больше времени займёт их загрузка.

      В общем, в зависимости от того что нам важнее — гибкость или скорость — можно использовать либо allurectl watch, либо allurectl upload. Мы в разных сервисах используем разные команды.

Мы ещё добавляли шаг для отображения ссылки на запуск прямо в GitHub, чтобы не нужно было искать конкретный прогон в Allure и можно было по прямой ссылке могли перейти к запуску. Может выглядеть примерно так:

- name: Get launch url
        if: ${{ always() && steps.run-backend-component-tests.outcome != 'skipped'}}
        run: |
          export $(allurectl job-run env | grep ALLURE_LAUNCH_URL)
          echo "### [Test results](http://${ALLURE_LAUNCH_URL:8})" >> $GITHUB_STEP_SUMMARY

Запускаем тесты и получаем результаты

Собственно, делаем пуш в репу и запускаем тесты.

Что получилось

Всё получилось, теперь все автотесты генерируют тест-кейсы и складывают их в TestOps. А мы наслаждаемся свободным временем, ведь больше не нужно поддерживать автоматизированные тест-кейсы. Осталось автоматизацию довести до 100% и нас уволят (шутка).

Если серьёзно, то мы подключили 23 сервиса, в которых есть тесты. В 15 из них мы разметили в тестах шаги, и теперь там автоматически генерируются тест-кейсы.

Максимальное количество тестов в одном сервисе — 19751, а минимальное — 2.

Максимальное количество запусков в одном сервисе — 23046, а минимальное — 13.

Что не получилось

Я прикрутил Allure к юнит-тестам в своих проектах, но спустя 2 месяца выпилили обратно. Потому что юнит-тесты не флакуют, нам не нужно видеть историю их прогона. А размечать юнит-тесты в БДД-стиле, как советуют авторы BDD in action, я ещё не готов. Хотя идея в целом интересная, если нужно экстремальное понимание, что у нас проверяется.

Ещё мы столкнулись с проблемой, что если перезапустить билд с упавшими тестами (именно re-run сделать), то результаты предыдущего запуска перетрутся. Пока не знаем, что с этим делать.

Если у вас используется не NUnut, а xUnit, то важно знать, что Allure xUnit не работает нормально с параметризированными тестами, если в параметрах что-то отличное от строки. Есть пару вариантов решения - перейти как мы на NUnit, убрать такие тесты, либо пофиксить это и законтрибьютить в проект. В одном из проектов я выбрал мигрировать с xUnit на NUnit.

Пока непонятно, как вообще реализовать подход «тест-кейсы как код», чтобы ручные тест-кейсы тоже лежали рядом с кодом. Если кто-то уже реализовывал, напишите в комментариях или мне в Телеграм — очень интересно как это можно осуществить.


Кроме Хабра я пишу в телеграм-канал QAжется работает, подписывайтесь. Там я недавно рассказывал про четыре изменения, которые мы сделали в опенсорсном Allure.

Комментарии (0)