![](https://habrastorage.org/getpro/habr/upload_files/bb3/e4e/802/bb3e4e80270756fe65b1de5e97873434.png)
Внедрение автоматизированных практик тестирования — очень полезная штука. Однако при подходе к этой задаче возникает масса вопросов. Какую платформу выбрать? Сложной ли будет миграция? Какие подводные камни ждут впереди? В своем посте я расскажу, как мы переносили практику тестирования и внедряли «тесты как код» на базе 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.
![](https://habrastorage.org/getpro/habr/upload_files/8e6/293/5a3/8e62935a37abe6a83dfe0437e9d7d308.png)
При миграции из старой TMS для сохранения иерархии папок для тестовых моделей мы решили сделать маппинг с помощью аннотаций @Section … @Section2 и в итоге получили 3 уровня вложенности. Пример аннотации выглядит так:
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "section")
public @interface Section {
String value();
}
В самой TMS был настроен маппинг:
![](https://habrastorage.org/getpro/habr/upload_files/ad5/508/6ca/ad55086ca4acb00c0f1c60a4c76f2f3c.png)
Затем для удобства фильтрации тестов мы добавили @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 получаем внутри прогона подобный вид теста:
![](https://habrastorage.org/getpro/habr/upload_files/b12/147/3e0/b121473e0adc0d39b2df90985a4e8d53.png)
Рабочий цикл тестировщика выглядит теперь следующим образом:
![](https://habrastorage.org/getpro/habr/upload_files/efd/33f/1f7/efd33f1f7ecbb331b1c2d9f4301f0095.png)
На этапе Create test можно как написать ручной тест-кейс, так и сразу подготовить автотест. Все зависит от конкретной задачи и связанной с ней необходимости.
Сложности, с которыми мы столкнулись
1. Не все поля подлежат маппингу
Как оказалось, аллюр позволяет использовать поля Precondition и Expected result, но данные поля невозможно выгрузить из кода. Принимаем это как ограничение при построении тестов.
![](https://habrastorage.org/getpro/habr/upload_files/7d4/d95/bad/7d4d95badd863309fa3e86a31ad81264.png)
В коде просто добавляем шаги с описанием предусловий.
step("Предусловия", () -> {
step("Открыть приложение", () -> {});
});
2. Ручные тесты под видом автоматизированных
Оказалось, что все выгружаемые тесты (ручные и авто) воспринимаются Allure TestOps как автоматизированные. Из коробки готового примера или аннотации для формализации этого вопроса нет. Поэтому мы написали свою кастомную аннотацию.
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@LabelAnnotation(name = "ALLURE_MANUAL")
public @interface Manual {
boolean value();
}
В итоге происходит тестовый прогон с необходимой группой тестов, в которой сразу получаем результаты: автотестов, устаревших (отключенных) автотестов и ручных тестов, требующих прохождения.
![](https://habrastorage.org/getpro/habr/upload_files/c15/0f9/3e9/c150f93e9c7957cce21e66a2abc82f67.png)
Пока прогон не завершен, такие тесты отображаются со статусом «In progress» (синий цвет). После завершения прогона непройденные тесты получат статус «Unknown» и станут фиолетовыми.
![](https://habrastorage.org/getpro/habr/upload_files/251/0de/297/2510de29709653de2bf9b3b3750778fe.png)
Таким образом помечаем аннотацией @Manual(true)
соответствующий тестовый класс или тестовый метод, после чего получаем реальную картинку по количеству автотестов и ручных тестов в проекте.
![](https://habrastorage.org/getpro/habr/upload_files/1e8/135/ea4/1e8135ea441b162268fce3bbe8734534.png)
3. Вложения
Так и не получилось до конца побороть проблему вложений для тестов. Все вложения видны в результатах выполнения, но не отображаются в самом тесте. Это, конечно, не критично. Команда просто привыкла, что необходимо проваливаться в последний запуск теста и уже там смотреть, какой запрос нужно выполнить.
![](https://habrastorage.org/getpro/habr/upload_files/e15/cba/d9e/e15cbad9e3ac7aa0c7e20a57d93258e5.png)
При этом если перейти в результаты теста (синий линк), то вложения будут видны, и в данном случае это картинка.
![](https://habrastorage.org/getpro/habr/upload_files/b46/80b/891/b4680b8915ffe5e798ace209c9210d74.png)
4. Версионность тестов
Когда мы привыкли к тому, что тесты могут быть автоматизированы и превращены в код, возникла потребность сохранять различные версии тестов и иногда откатываться к старым или использовать наработки прошлого для подготовки новых тестов. В самой TMS Allure такой функции не предусмотрено. Но этот вопрос легко решается, если хранить версии тест-кейсов в гите. При желании и необходимости можно поддерживать их версионность с помощью веток.
Итоги
Внедрение подхода «тесты как код» сделало нашу работу быстрее, а также помогло навести порядок в достаточно объемной практике тестирования сразу для нескольких десятков команд.
В дополнение теперь при запуске автотестов какой-то группы (smoke, api и т. д.) мы получаем тестовый прогон, включающий все тесты: автоматизированные, устаревшие и ручные. Казалось бы, зачем это в прогоне? Устаревшие тесты маячат перед глазами и сподвигают на их скорейшую актуализацию, ручные сообщают нам о том, что необходимо пройти ручками какую-то часть функционала и отследить динамику автоматизации от прогона к прогону.
Кроме этого я бы хотел отметить еще пару полезных преимуществ нового подхода:
Если вам когда-либо приходилось массово рефакторить пример JSON’а для API-теста, ссылки на макеты или что-то иное, то теперь подобный рефакторинг сводится к простой массовой замене параметров в нужных файлах. И это делается намного быстрее подобных ручных изменений в TMS.
При разработке тестов мы получаем готовые шаблоны, которые затем можно автоматизировать, причем для этого не придется постоянно заходить в сам аллюр — всё перед глазами в IDE.
Абсолютно все, кто попробовал данный подход, оценили его удобство, снижение трудозатрат на написание и поддержку тест-кейсов. Это стало дополнительным подтверждением, что всё это действительно стоило провернуть.
P.S. А еще мы получили неожиданный эффект: ручные тестировщики начали активно погружаться в автоматизацию. Стоило им познакомиться с IDE, как пропали страхи перед кодингом.
Rampage
Спасибо за небольшой гайд по переезду на Allure TestOps. Мы как раз задумываемся об этом. Но по подходу есть сомнения. Писать тест-кейсы и поддерживать их через код - это конечно здорово, но аналитиков в код никогда не затащишь, а у нас они частенько накидывают критерии приемки в виде кейсов прямо в TMS.
AugustoZ Автор
Спасибо за комментарий. У нас так же всплывают подобные трудности, когда аналитики накидывают драфты в сам Аллюр. Мы нашли для себя решение в том, что есть возможность импорта тест-кейсов в сам код, но там так же есть подводные камни, связанные с маппингом и тем, что придется ручками прописывать теги или кастомизированные поля