Go, я создал: интегрируем Allure в Go красиво
Привет! Меня зовут Антон, я ведущий инженер по тестированию в 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:
Важно: не перегрузить интерфейс
Особое внимание мы уделили тому, чтобы не перегрузить интерфейс вложенными вызовами.
Давайте сравним с 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. Надеюсь, будет полезно. Ждём ваших пулл-реквестов.