Всем привет! Меня зовут Иван Чечиков, я QA lead в МТС Digital, работаю над проектом стримингового сервиса WASD.TV. В этой статье я поделюсь опытом внедрения системы управления тестированием (TMS) Allure TestOps в наш проект и расскажу, что из этого получилось. А еще отмечу подводные камни, с которыми мы столкнулись и обозначу пути их обхода. Статья может быть полезна тем, кто задумываются о переходе на данную TMS с других готовых решений, таких так Zephyr, TestRail, Test IT.
Allure TestOps – это коробочное решение, позволяющее управлять как ручным, так и автоматизированным тестированием: создавать тест-кейсы и чек-листы, запускать ручные и автоматические прогоны, заводить дефекты и собирать статистику по проделанной работе. Также у Allure большой набор интеграций с различными инструментами и языками программирования.
В нашем проекте для QA мы используем Jira Server, Confluence, Jenkins CI/CD, автотесты на Java + Maven + Cucumber + Gherkin + Serenity RestAssured (для API тестов) и Selenium (для UI тестов). Как основную TMS применяли плагин Zephyr для Jira, но нам предстоял переезд на Allure Test Ops. Что делать в таком случае?
Нужно настроить интеграцию с Jira Server и Allure TestOps.
Нужно перенести существующие тестовые артефакты из надстройки Zephyr в Jira в Allure TestOps и уйти в дальнейшем от Zephyr.
Нужно настроить запуск автотестов в Allure TestOps, подружив его с нашей джобой в Jenkins CI/CD и получать результаты прогонов. На данный момент мы работаем с Gitlab CI/CD, но опыт с Jenkins был также уникален для нас.
Объединить ручные и автотесты в один проект в Allure TestOps.
Написать инструкции для QA-инженеров по использованию Allure Test Ops
Начать работать в Allure TestOps.
Собрать первые метрики по проделанной работе.
Разберем каждый этап подробно:
Интеграция с Jira Server или Jira Cloud – дело несложное, выполняется как на стороне Allure, так и на стороне Jira. Создаем интеграцию с Jira в Allure TestOps, указываем креды и эндпоинт Jira Server.
Allure TestOps
В Jira в панели Администратора необходимо установить плагин Allure TestOps for JIRA
Указываем эндпоинты Allure Test Ops, выбираем версию 4.x.x и проставляем id интеграции Jira в Allure. Ссылка на официальный мануал.
Jira Server
Единственное замечание – желательно иметь актуальную версию Jira не ниже 8.4 (Jira Server) и Allure TestOps не ниже 4.2.2, иначе интеграция может быть неполноценной, у нас, к примеру, не отображались прогоны с Allure в Jira.
Результаты интеграции: отображение прогонов и тестовой документации из Allure в Jira.
Кейсы из плагина Zephyr в Jira мы переносили через скрипт Qameta, для нас его существование было неочевидным, поэтому пришлось писать в поддержку. Скрипт лежит на сайте у разработчиков, миграцию мы делали на удаленной машине, имеющей доступы к эндпоинтам Allure и Jira. Вызывали скрипт, передавая json в виде конфига.
java -jar allure-testops-migration-2.9.5.jar config
Проблем с миграцией не было. Все наши 2000 с лишним кейсов мигрировали в Test Cases Allure TestOps, все поля тестовых артефактов были перенесены.
Интеграция с Jenkins CI/CD заняла значительное количество времени. Проблемы были как с самой джобой дженкинса, так и с конфигурацией кода проекта. Подружить Jenkins и Allure TestOps на уровне интеграции не так сложно.
В Jenkins CI/CD в разделе плагинов устанавливаем плагин Allure TestOps for Jenkins последней версии. Это важно, так как может не произойти выгрузка результатов автотестов в Allure TestOps.
Jenkins
В настройках системы в Jenkins указываем эндпоинт Allure TestOps и админские креды.
В Allure Test Ops прописываем эндпоинт Jenkins.
У нас автотесты на Java с использованием Maven, Cucumber, Gherkin, Serenity и Selenium. Для получения результатов в Allure с прогонов автотестов пришлось править конфигурационный файл pom.xml. Я добавил зависимости:
pom.xml
<dependencies>
......
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit4-aspect</artifactId>
<version>2.0-BETA15</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-rest-assured</artifactId>
<version>2.18.1</version>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-cucumber5-jvm</artifactId>
<version>2.18.0</version>
</dependency>
......
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<forkCount>3</forkCount>
<reuseForks>true</reuseForks>
<argLine>-Xmx1024m -XX:MaxPermSize=256m</argLine>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>**/*${type.of.suite}.java</include>
</includes>
<systemPropertyVariables>
<webdriver.base.url>${webdriver.base.url}</webdriver.base.url>
<allure.results.directory>${project.build.directory}/allure-results</allure.results.directory>
</systemPropertyVariables>
<parallel>classes</parallel>
<threadCount>${parallel.tests}</threadCount>
<forkCount>${parallel.tests}</forkCount>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
</dependencies>
<executions>
<execution>
<goals>
<goal>test</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Чтобы все это добро заработало в Cucumber – пришлось прописывать плагины для API и Ui-классов.
ApiCucumberTestSuite.java
package starter.runner.api;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
plugin = {"io.qameta.allure.cucumber5jvm.AllureCucumber5Jvm"},
features = "src/test/resources/features/api/",
glue = {"starter"}
)
public class ApiCucumberTestSuite {}
UiCucumberTestSuite.java
package starter.runner.ui;
import io.cucumber.junit.Cucumber;
import io.cucumber.junit.CucumberOptions;
import org.junit.runner.RunWith;
@RunWith(Cucumber.class)
@CucumberOptions(
plugin = {"io.qameta.allure.cucumber5jvm.AllureCucumber5Jvm"},
features = "src/test/resources/features/ui/",
glue = {"starter"}
)
public class UiCucumberTestSuite {}
Для определения типов тестов добавил аннотации allure.label.layer в features файлы.
authorizationApi.feature
@auth @api @all @smoke @allure.label.layer=Api
Функция: Авторизация
Пользователь делает авторизацию через API
@positive @api
Структура сценария: успешная авторизация
Когда <User> делает авторизацию через API
Тогда пользователь получает access token
Примеры:
| User |
| user1 |
authorizationUi.feature
@auth @ui @all @allure.label.layer=Ui
Функция: Авторизация
Пользователь авторизуется
@positive @ui
Структура сценария: успешная авторизация
Дано пользователь переходит на главную страницу
Когда пользователь авторизуется под юзером <User>
Тогда пользователь проверяет, что отображается имя юзера <User>
Примеры:
| User |
| user1 |
| user3 |
Для логирования API тестов через SerenityRest в Allure TestOps добавил в коде в респонсы фильтр с AllureRestAssured.
ApiAuthorizationStepDefinitions.java
......
JSONObject requestBody = new JSONObject();
requestBody.put("user_email", user_email);
requestBody.put("user_password", user_password);
response = SerenityRest.given().filter(new AllureRestAssured()).log().all().
and().
body(requestBody.toMap()).
contentType(ContentType.JSON).
post(EndPoints.tokens);
......
Для логирования UI-тестов через Selenium в Allure TestOps добавил в коде шаги с получением скрина текущей страницы с помощью класса AllureForScreenshot.
AllureForScreenshot.java
package allure;
import io.qameta.allure.Allure;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class AllureForScreenshot {
public void takeScreenshot(WebDriver webDriver) throws FileNotFoundException {
File screenshotAs = ((TakesScreenshot) webDriver).getScreenshotAs(OutputType.FILE);
Allure.addAttachment("Screenshot", new FileInputStream(screenshotAs));
}
}
UiAuthorizationStepDefinitions.java
......
switch (user) {
case "user1":
allureForScreenshot.takeScreenshot(mainPage.getDriver());
mainPage.openAuthForm();
allureForScreenshot.takeScreenshot(authorizationPage.getDriver());
authorizationPage.fillEmailField(user1Email);
allureForScreenshot.takeScreenshot(authorizationPage.getDriver());
authorizationPage.clickAuthLoginButton();
allureForScreenshot.takeScreenshot(authorizationPage.getDriver());
authorizationPage.clickPasswordButton();
allureForScreenshot.takeScreenshot(authorizationPage.getDriver());
authorizationPage.fillPassField(user1Pass);
allureForScreenshot.takeScreenshot(authorizationPage.getDriver());
authorizationPage.clickOnEnterButton();
break;
......
Результаты работы API и UI-тестов:
С джобой в Jenkins пришлось повозиться. Она была не параметризированная, параметры задавались на каждом шаге, логика работы билда лежала в Jenkinsfile. Allure TestOps не умеет работать с такими сборками, так как при запуске джобы из Allure она тупо висела в Jenkins на первом шаге, ожидая в интерфейсе ввода значения. Решение было простым – переписать логику Jenkinsfile под параметризированную сборку и поменять тип билда в Jenkins.
Jenkins
Jenkinsfile
pipeline {
agent any
parameters {
gitParameter branchFilter: 'origin/(.*)', defaultValue: '', name: 'BRANCH', type: 'PT_BRANCH'
choice(name: 'TEST_SUITE', choices: ['TestSuite', 'Parallel'], description: 'Выберите способ запуска тестов')
choice(name: 'TYPE_OF_TESTS', choices: ['@api', '@ui'], description: 'Выберите тип тестов')
choice(name: 'MODULE_OF_TESTS', choices: ['Список модулей тестов через @'],
description: 'Выберите модуль тестов')
choice(name: 'ENV_1', choices: ['Список тестовых стендов'],
description: 'Выберите стенд')
}
stages {
stage("Run tests") {
steps {
script {
def inptext = readFile file: "serenity.properties"
inptext = inptext.replaceAll("env1", "${params.ENV_1}")
writeFile file: "serenity.properties", text: inptext
sh """ls ./"""
wrap([$class: 'Xvfb', additionalOptions: '', assignedLabels: '', displayNameOffset: 3, installationName:
'xvfb', parallelBuild: true, screen: '1600x1200x24']) {
sh 'printenv'
sh """mvn clean verify -Dcucumber.options=\"--tags '${params.MODULE_OF_TESTS} and ${params.TYPE_OF_TESTS}'\" -Denvironment=${params.ENV_1} -Dtype.of.suite=${params.TEST_SUITE}"""
}
}
}
}
}
post {
always {
withAllureUpload(indexExistingFiles: true, serverId: 'Id сервера в Allure TestOps', projectId: 'Номер проекта в Allure TestOps',
results: [
[path: 'target/allure-results']
]) {
}
}
}
}
Результаты прогона отправляются на последнем этапе работы билда. Внешний вид прогонов в Jenkins:
Джоба в Allure TestOps имеет вид:
Мы запускаем билд через параметры в environment. Это удобно, так как можно создать значения в данной форме, которые будут выбираться из выпадающего списка, исключая повторный ввод вручную. Есть нюанс с дефолтными полями: Device, OS, Host, Browser, Environment – к сожалению, их нельзя удалить либо отключить, если они не используются. Приходится игнорировать их при запуске джобы.
Внешний вид прогона в Allure TestOps:
Под ручные и авто тесты я создал один общий проект.
Разделил в фильтрах ручные тестовые артефакты по командам, внутри каждой команды тест кейсы и чек-листы разделены по функционалу. Автоматизированные кейсы лежат в отдельных фильтрах (API, UI). В ближайшем будущем планирую также разделить их по командам.
В Allure TestOps по дефолту три уровня вложенности и есть шаблон под тестовые артефакты (тест-кейсы, чек-листы).
В самом тестовом артефакте можно:
проставлять различные тэги;
линковать его с тасками в багтрекере;
писать в нем комментарии
прикреплять файлы и изображения;
вешать различные роли (владелец, ревьювер и прочие, в зависимости от флоу тестирования);
менять его статусы;
создавать с ним ручные и авто прогоны, линковать их в той же Jira, выполнять по шагам, проставляя статусы (Passed, Failed, Skipped и прочие).
Также присутствует возможность заведения дефектов параллельно с созданием сущностей в Jira.
Allure TestOps позволяет отслеживать статусы заведенных дефектов в багтрекере (что крайне удобно) для своевременного их закрытия в Allure.
Инструкции мы создали в Confluence, провели QA-ретро и познакомились всем отделом качества с функционалом Allure TestOps.
Начали работать с Allure. Наш флоу: анализ задачи, написание тестовой документации, командное кроссревью, созданного тестового артефакта, ручное тестирование, автоматизированное тестирование (смоук, регресс), деплой. Какие трудности мы испытали:
нельзя переносить папки с тестовыми артефактами в интерфейсе Allure;
заведение дефектов параллельно с созданием задач в Jira вызывает дискомфорт, так как требуется переход в баг-трекер для дозаполнения тасок;
не хватает почтовых уведомлений при ревью тестовой документации, да и вообще для любых изменений в TMS;
в нашем случае для запуска джобы автотестов было бы удобно создавать несколько environments, тем самым запуская за раз несколько билдов в Jenkins, но у нас так не работает;
не хватает аналитики по заведенным дефектам
хотелось бы метрики с дашбордов экспортировать в pdf для передачи отчетов заинтересованным лицам
Прошел спринт и я собрал первые метрики по проделанной работе QA-отдела. Для этого в Allure TestOps можно создавать отдельные дашборды на главной странице проекта и с помощью AQL помещать в них диаграммы по сущностям Allure. Результаты радуют, QA активно работают в новой TMS, выполняют ручные и автоматизированные прогоны, заводят дефекты. Чего не хватает для сбора аналитики: AQL для заведенных в Allure TestOps багов и их параметров, но вроде бы Qameta скоро релизнет такой функционал.
Итог: с момента самостоятельного внедрения Allure TestOps до запуска проекта и начала работы в нем прошло порядка двух месяцев. Большое спасибо компании Qameta за предоставленный продукт, а команде поддержке за своевременную и полноценную помощь. Мы получили уникальный и полезный опыт при работе с продуктом. Ждем с нетерпением новых релизов и пользуемся тем, что уже есть!
Спасибо за уделенное время, если у вас есть вопросы – буду рад на них ответить в комментариях.