Tests as code с Allure TestOps и что из этого вышло
Внедрение автоматизированных практик тестирования — очень полезная штука. Однако при подходе к этой задаче возникает масса вопросов. Какую платформу выбрать? Сложной ли будет миграция? Какие подводные камни ждут впереди? В своем посте я расскажу, как мы переносили практику тестирования и внедряли «тесты как код» на базе Allure TestOps.
Достаточно давно (по меркам ИТ-мира) я посмотрел доклад Артема Ерошенко с Heisenbug 2020 «Тест-кейсы как код». С переходом в Леруа Мерлен со старой TMS на Allure TestOps появилось желание полноценно попробовать данный подход у себя. В статье расскажу о том, что из этого получилось.
Привет, Хабр! Меня зовут Сергей Старков, я работаю в области тестирования с 2011 года. Ранее тестировал: десктопные клиент-серверные системы видеонаблюдения вместе с железом для них, кассовое ПО (Windows и DOS) вместе с железом, распределенный монолит, в основе которого Oracle Siebel CRM. В Леруа Мерлен являюсь инженером по тестированию различных продуктов для внутренних и внешних пользователей.
Переезд на новую TMS?
Не хотелось бы устраивать холивары по выбору TMS-системы. Скажу сразу, что наш приоритет был определен очень прагматично. Allure TestOps по сумме лицензий выходил дешевле своих конкурентов, поддерживать этот продукт проще, а еще он находится полностью в нашей зоне ответственности, также в плюс интуитивно понятный интерфейс и то, что очень просто использовать внешние интеграции с Jira, Jenkins и т. д.
Понятно, что переезд нескольких десятков команд, сотни проектов с тестовой базой, состоящей из десятков тысяч тест-кейсов, пугал, но мы справились — чему сейчас очень рады.
Чего мы ждали от подхода «тесты как код»
IT-составляющая в Леруа Мерлен последние пару лет развивается очень быстрыми темпами. Поэтому нам хотелось сформировать единый подход к написанию тест-кейсов. Кроме того, была надежда снизить трудозатраты на их написание и рефакторинг, а также косвенно увеличить скорость актуализации тестов. Ну и конечно, всё это было сдобрено духом авантюризма: «А что из этого выйдет?»
У нас имеется классический CI/CD, когда по мержу в ветку (например, dev) происходит запуск статического анализа кода приложения, различные проверки информационной безопасности, прогоняются unit-тесты и, наконец, раскатка на соответствующее окружение. После этого запускаются функциональные тесты, и результаты попадают в Allure TestOps. Плюс, при желании, можно запланировать дополнительные уведомления в Slack.
При миграции из старой TMS для сохранения иерархии папок для тестовых моделей мы решили сделать маппинг с помощью аннотаций @Section… @Section2 и в итоге получили 3 уровня вложенности. Пример аннотации выглядит так:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "section")
public @interface Section {
String value();
}
В самой TMS был настроен маппинг:
Затем для удобства фильтрации тестов мы добавили @Layer и настроили необходимый маппинг.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "layer")
public @interface Layer {
String value();
}
Для удобства отображения ссылок на задачи в Jira добавлены были аннотации @JiraIssues и @JiraIssue, а также маппинг в Issue Schemas.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface JiraIssues {
JiraIssue [] value();
}
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "jira")
@Repeatable(JiraIssues.class)
public @interface JiraIssue {
String value();
}
В итоге пример ручного теста получился таким:
@Test()
@AllureId("87996")
@Section("Тесты примеры")
@Section1("API тесты")
@JiraIssues({@JiraIssue("TEST-2")})
@Links({@Link("TEST-2")})_____________________________________________________________
@Tags({@Tag("example")})
@Layer("api")
@DisplayName("Пример API теста")
public void apiTestExample() {
step("Отправить запрос GET /v1/addresses/store=999&lmCode=10966327", () -> {
});
step("Проверить:", () -> {
step("Получили httpcode=200", () -> {});
step("В ответе вернулся json:", () -> {
file.attachFile("Ответ", "examples/example_response.json", "json");
});
});
}
После выгрузки результатов в сам Allure TestOps получаем внутри прогона подобный вид теста:
Рабочий цикл тестировщика выглядит теперь следующим образом:
На этапе Create test можно как написать ручной тест-кейс, так и сразу подготовить автотест. Все зависит от конкретной задачи и связанной с ней необходимости.
Сложности, с которыми мы столкнулись
1. Не все поля подлежат маппингу
Как оказалось, аллюр позволяет использовать поля Precondition и Expected result, но данные поля невозможно выгрузить из кода. Принимаем это как ограничение при построении тестов.
В коде просто добавляем шаги с описанием предусловий.
step("Предусловия", () -> {
step("Открыть приложение", () -> {});
});
2. Ручные тесты под видом автоматизированных
Оказалось, что все выгружаемые тесты (ручные и авто) воспринимаются Allure TestOps как автоматизированные. Из коробки готового примера или аннотации для формализации этого вопроса нет. Поэтому мы написали свою кастомную аннотацию.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "ALLURE_MANUAL")
public @interface Manual {
boolean value();
}
В итоге происходит тестовый прогон с необходимой группой тестов, в которой сразу получаем результаты: автотестов, устаревших (отключенных) автотестов и ручных тестов, требующих прохождения.
Пока прогон не завершен, такие тесты отображаются со статусом «In progress» (синий цвет). После завершения прогона непройденные тесты получат статус «Unknown» и станут фиолетовыми.
Таким образом помечаем аннотацией @Manual(true)
соответствующий тестовый класс или тестовый метод, после чего получаем реальную картинку по количеству автотестов и ручных тестов в проекте.
3. Вложения
Так и не получилось до конца побороть проблему вложений для тестов. Все вложения видны в результатах выполнения, но не отображаются в самом тесте. Это, конечно, не критично. Команда просто привыкла, что необходимо проваливаться в последний запуск теста и уже там смотреть, какой запрос нужно выполнить.
При этом если перейти в результаты теста (синий линк), то вложения будут видны, и в данном случае это картинка.
4. Версионность тестов
Когда мы привыкли к тому, что тесты могут быть автоматизированы и превращены в код, возникла потребность сохранять различные версии тестов и иногда откатываться к старым или использовать наработки прошлого для подготовки новых тестов. В самой TMS Allure такой функции не предусмотрено. Но этот вопрос легко решается, если хранить версии тест-кейсов в гите. При желании и необходимости можно поддерживать их версионность с помощью веток.
Итоги
Внедрение подхода «тесты как код» сделало нашу работу быстрее, а также помогло навести порядок в достаточно объемной практике тестирования сразу для нескольких десятков команд.
В дополнение теперь при запуске автотестов какой-то группы (smoke, api и т. д.) мы получаем тестовый прогон, включающий все тесты: автоматизированные, устаревшие и ручные. Казалось бы, зачем это в прогоне? Устаревшие тесты маячат перед глазами и сподвигают на их скорейшую актуализацию, ручные сообщают нам о том, что необходимо пройти ручками какую-то часть функционала и отследить динамику автоматизации от прогона к прогону.
Кроме этого я бы хотел отметить еще пару полезных преимуществ нового подхода:
Если вам когда-либо приходилось массово рефакторить пример JSON«а для API-теста, ссылки на макеты или что-то иное, то теперь подобный рефакторинг сводится к простой массовой замене параметров в нужных файлах. И это делается намного быстрее подобных ручных изменений в TMS.
При разработке тестов мы получаем готовые шаблоны, которые затем можно автоматизировать, причем для этого не придется постоянно заходить в сам аллюр — всё перед глазами в IDE.
Абсолютно все, кто попробовал данный подход, оценили его удобство, снижение трудозатрат на написание и поддержку тест-кейсов. Это стало дополнительным подтверждением, что всё это действительно стоило провернуть.
P.S. А еще мы получили неожиданный эффект: ручные тестировщики начали активно погружаться в автоматизацию. Стоило им познакомиться с IDE, как пропали страхи перед кодингом.