Go, я создал: интегрируем Allure в Go красиво

bcaf1ac5b16b56c8ee35c18393e23537.jpg

Привет! Меня зовут Антон, я ведущий инженер по тестированию в Ozon: занимаюсь созданием и поддержкой end-to-end Go-тестов бэкенда для QA.

Мы довольно долго писали тесты в основном на Python. Go — молодой язык, и популярных устоявшихся инструментов у него пока немного. В Python есть pytest, в Java — JUnit и TestNG, в Go — пока что весьма свободно. 

Однажды, в очередной раз переписав группу старых Python-тестов, я решил, что надо что-то менять. Эта мысль в итоге привела меня к созданию нашей собственной опенсорс-библиотеки — с поддержкой Allure без перегрузки интерфейса, инфраструктурой для хранения тестов как в одних репозиториях с сервисами, так и в отдельных, репортами в Slack и разными другими штуками.

Почему мы всё-таки решили создать своё решение, с какими сложностями пришлось разбираться в процессе и как это может пригодиться вам для тестов на Go, я расскажу в этой и следующих статьях. Сегодня — об интеграции с Allure.

Для контекста: Go в Ozon 

Большая часть сервисов в Ozon написана на Go, и со временем их количество только растёт. 

Профит от Go в сервисах:

  • инфраструктура: относительно лёгкий докер, отлаженные джобы в GitLab CI для запуска интеграционных и юнит-тестов, линтеринг и код-ревью;

  • пакетная система на Git-репозиториях: не нужно забивать себе голову хранением и импортом вспомогательных библиотек; удобная система версионирования, основанная на Git-тегах;

  • относительно низкий порог входа: можно нанимать людей и доучивать их до нужного уровня в Go — довольно легко и почти безболезненно.

Всё это на руку нам в E2E-тестах: можно поднимать вспомогательные сервисы, писать библиотеки и службы — и использовать для этого инструменты разработчиков.

Вот только потенциал этот мы использовали не в полной мере: разработку вели на Go, а тесты писали на Python. Это был не всегда удобный, но привычный сценарий для E2E-тестирования на фоне небольшого числа готовых инструментов, которые предоставлял язык на тот момент. 

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

Первым делом: поддержка Allure 

Итак, мы задались вопросом об альтернативе Python для тестирования Go-бэкенда. 

Первый шаг — сформулировать требования, чего мы хотим от альтернативного инструментария.

Тесты должны писаться легко и быстро (а значит, быть недорогими в поддержке). Инструменты должны быть простыми и понятными для людей из разных команд с разным бэкграундом.

Но главное — поддержка Allure. Мы в Ozon активно его используем для сбора статистики и аналитики по тестам. 

Изучив опыт коллег (привет, Vivid Money и Lamoda тут на Хабре) и проведя исследование, я обнаружил следующее:

  • официального решения Allure для Go на тот момент не существовало;

  • провайдеры есть (например, dailymotion/allure-go), но мне решительно не нравился их интерфейс, или они давно не обновлялись, как будто их перестали поддерживать (GabbyyLS/allure-go-common);

  • фреймворков тестирования не так много, самым перспективным выглядел Testify.

Ну что ж, тогда напишем свой провайдер для ​​Allure. 

Нам потребуется:

  • пробрасывать Allure-отчёты;

  • компоновать тесты;

  • запускать тесты.

Была надежда, что компоновку и запуск удастся сделать на Testify, но выяснилось, что тот не поддерживает плагины. Окей, напишем сами.

Так и появился наш опенсорс-проект Allure-Go.

Покажу несколько примеров его использования.

Что именно делает Allure-Go

Во-первых, как и Testify, наша библиотека позволяет организовывать тесты в тестовые классы структуры. Это делает код тестов понятнее и помогает явно выделять тест-комплекты, использовать Before и After-хуки. При этом сохраняется возможность более привычного для Go написания тестов как функций (также с использованием этих хуков).

Пример тестовой структуры:

type SuiteStruct struct {
  suite.Suite
}

func (s *SuiteStruct) Test1() {
}

func (s *SuiteStruct) Test2() {
}

func TestRun(t *testing.T) {
  runner.RunSuite(t, new(SuiteStruct))
}

Пример теста-функции:  

func TestSampleDemo(t *testing.T) {
  r := runner.NewTestRunner(realT)

  r.WithBeforeEach(func(t *provider.T) {})

  r.WithAfterEach(func(t *provider.T) {})

  r.Run("My test 1", func(t *provider.T) {})
  r.Run("My test 2", func(t *provider.T) {})
  r.Run("My test 3", func(t *provider.T) {})
}

Кроме того, Allure-Go предоставляет разные возможности для работы с шагами и Allure-лейблами. Интерфейс мы постарались сделать максимально лаконичным и user-friendly, прокинули через обёртки provider.T и suite.Suite.

Пример простого теста с вложенными шагами:

type StepTreeDemoSuite struct {
  suite.Suite
}

func (s *StepTreeDemoSuite) TestInnerSteps() {
  s.Epic("Demo")
  s.Feature("Inner Steps")
  s.Title("Simple Nesting")
  s.Description(`
     Step A is parent step for Step B and Step C
     Call order will be saved in allure report
     A -> (B, C)`)
  
  s.Tags("Steps", "Nesting")

  s.WithNewStep("Step A", func() {
     s.NewStep("Step B")
     s.NewStep("Step C")
  })
}

Ответ от Allure:

8523a2e4df5aa162ca3d926b9fd52fbe.png

Важно: не перегрузить интерфейс

Особое внимание мы уделили тому, чтобы не перегрузить интерфейс вложенными вызовами.

Давайте сравним с dailymotion:

func TestNewTest(t *testing.T) {
  allure.Test(
     t,
     allure.Description("New Test Description"),
     allure.Action(func() {
        allure.Step(
           allure.Description("Step description"),
           allure.Action(func() {
             
           }))
     }))
}

То же самое в Allure-Go:

type SuiteStruct struct {
  suite.Suite
}

func (s *SuiteStruct) TestNewTest() {
  s.Description("New Test Description")
  s.WithNewStep("Step description", func() {

  })
}

Кажется, стало лаконичнее.

Что мы получили

За полгода в продакшене — 0 проблем с заливкой отчётов, минимальный порог вхождения. Как следствие, коллеги стали интересоваться решением — на сегодняшний день втянулось и переехало более 30 команд в Ozon.

Прямо сейчас Allure-Go умеет следующее:

  • интегрировать Allure в Go-тесты (поддерживает шаги и аттачи, предлагает лаконичный интерфейс);

  • собирать тесты в сьюты;

  • запускать тесты в Go.

Планы:

  • зарелизить нашу библиотеку в официальный репозиторий Allure (Qameta Software);

  • добавить новые фичи: асинхронные степы через конструкцию запуска goroutine; обёртка ассертов в шаги (на базе ассертов Testify), прокидывание интерфейсов для упрощения расширения и другие.

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

Главный результат, на мой взгляд: мы сделали ещё один шаг в сторону реальности, в которой Dev и QA говорят на одном языке. Разработчики помогают с поддержкой и развитием тестов, тестировщики шире и глубже ориентируются в кодовой базе. 

В следующих эпизодах поговорим об инфраструктуре, репортах и безопасности. Оставайтесь с нами!  

Короче, встречайте

Allure-Go на GitHub. Надеюсь, будет полезно. Ждём ваших пулл-реквестов. 

© Habrahabr.ru