Ускоряем работу с тестовой документацией. Экспорт данных из Allure-отчета в Confluence

от автора

Для того, чтобы ускорить тестирование крупных приложений, как правило, проверки вручную сочетают с автотестами. После их прогона QA или SDET-специалисты разбирают успешные и «упавшие» тесты – их нужно проверить вручную и зафиксировать результаты, например, в Confluence.

Рассмотрим на примере, как можно ускорить экспорт этих данных, если вы работаете с некоммерческой версией Allure Framework. При использовании Allure-EE такие доработки не нужны – информацию по ручному прохождению кейсов можно хранить в самих отчетах.

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

Задачи, которые нам требовалось решить:

  • Найти и структурировать необходимые данные из json-файлов, которые создает Allure.

  • Сгенерировать html-код таблицы, используя полученные ранее данные.

  • Создать таблицу в Confluence с помощью POST-запроса, в теле которого передать html-код таблицы.

Получение данных из json-файлов

Json-файлы с которыми мы будем работать, находятся в каталоге allure-report\data\test-cases

Для каждого автотеста создается отдельный json-файл с информацией по его прохождению. Это достаточно большой файл, который содержит все шаги автотеста, поэтому в статье мы не будем приводить его полностью. Нас интересуют такие параметры:

"status" : "failed”, "name" : "Test_0001",  {     "name" : "epic",     "value" : "iOS" },  {     "name" : "feature",     "value" : "Авторизация" },  {     "name" : "story",     "value" : "Превышение попыток" }

Эти данные будем размещать во 2 — 5 колонках таблицы, используя определенные цвета для заливки фона ячеек. Статус автотеста может иметь несколько значений: «failed» (выделяем красным), «unknown» (фиолетовый), «broken» (желтый), «skipped» (серый).

Создадим два класса с моделями. Для генерации моделей удобно использовать IntelliJ IDEA плагин RoboPOJOGenerator. Также обратимся к Lombok, чтобы не создавать методы геттеры.

import com.google.gson.annotations.SerializedName; import lombok.Getter;  import java.util.List;  @Getter public class TestCase {    private String epic;    private String feature;    private String story;     @SerializedName("name")    private String name;     @SerializedName("status")    private String status;     @SerializedName("labels")    private List<LabelsItem> labels;     public void initLabels() {        if (labels != null) {            for (LabelsItem labelsItem : labels) {                switch (labelsItem.getName()) {                    case "epic" : epic = labelsItem.getValue();                        break;                    case "feature" : feature = labelsItem.getValue();                        break;                    case "story" : story = labelsItem.getValue();                }            }        }    } }   import com.google.gson.annotations.SerializedName; import lombok.Getter;  @Getter public class LabelsItem {    @SerializedName("name")   private String name;    @SerializedName("value")   private String value; }

Создадим метод, который будет получать эти параметры из json-файла. Преобразовывать json в класс модели будем при помощи Gson.

/** * Получает данные из json файла * * @param path путь к папке с файлами * @return данные из json файла */ public static TestCase readTestCasesJson(String path) {    try (Stream<String> stream = Files.lines(Paths.get(path))) {        String text = stream.reduce("", String::concat);        return new Gson().fromJson(text, TestCase.class);    } catch (IOException e) {        throw new RuntimeException(e.getMessage());    } }

Для получения списка всех json-файлов воспользуемся следующим методом:

/** * Получает список названий файлов в папке * * @param path путь к папке с файлами * @return список названий файлов * @throws IOException ошибка доступа к данным */ public static List<Path> getFilesInFolder(String path) throws IOException {    return Files.walk(Paths.get(path))            .filter(Files::isRegularFile)            .collect(Collectors.toList()); }

Теперь создадим метод, который будет собирать данные по всем упавшим тестам.

/** * Получает данные по всем упавшим * * @param paths путь к папке с файлами * @return список с данными по упавшим тестам */ public static List<TestCase> getTestCasesDataInFolder(List<Path> paths) {    List<TestCase> testCases = new ArrayList<>();    TestCase testCase;     for (Path path : paths) {        testCase = readTestCasesJson(path.toString());         if (!testCase.getStatus().equals("passed") ) {            testCase.initLabels();            testCases.add(testCase);        }    }     return testCases; }

Генерация таблицы

Далее создадим метод, который будет получать информацию по автотестам для всех статусов, сортировать их и создавать таблицу в формате html.

/**      * Формирует html код таблицы      *      * @param testCasesPath путь к папке с json файлами отчета      * @param link ссылка на прогон в CI      * @param name название прогона      * @return строка с html кодом таблицы      * @throws IOException ошибка доступа к данным      */     public static String createTableBody(String testCasesPath, String link, String name) throws IOException {          List<Path> filesPath = getFilesInFolder(testCasesPath);         List<TestCase> tests = getTestCasesDataInFolder(filesPath);          List<TestCase> notPassed = tests.stream()                 .sorted(Comparator.comparing(TestCase::getStatus)                         .thenComparing(TestCase::getEpic, nullsFirst(naturalOrder()))                         .thenComparing(TestCase::getFeature, nullsFirst(naturalOrder()))                         .thenComparing(TestCase::getStory, nullsFirst(naturalOrder()))                         .thenComparing(TestCase::getName, nullsFirst(naturalOrder())))                 .collect(Collectors.toList());          String lines = createTableLines(notPassed);          return (format(TABLE_HEADER, name, link, link) + lines + TABLE_TAIL).replace("\"", "\\\"");     }

Для формирования строк таблицы используем следующий метод:

/** * Формирует строки таблицы в Confluence * * @param testsCases список упавших тестов * @return html код строк таблицы */ private static String createTableLines(List<TestCase> testsCases) {    StringBuilder result = new StringBuilder();    String colorValue = "";     for (TestCase test : testsCases) {        colorValue = getColorValue(test.getStatus());         result.append(                    format(                            TABLE_LINE,                            ++testNumber,                            Strings.isNotNullAndNotEmpty(test.getEpic()) ? test.getEpic() : " ",                            Strings.isNotNullAndNotEmpty(test.getFeature()) ? test.getFeature() : " ",                            Strings.isNotNullAndNotEmpty(test.getStory()) ? test.getStory() : " ",                            colorValue,                            getColorName(test.getStatus()),                            colorValue,                            test.getName()                    )        );    }     return result.toString(); }

Для создания html-кода таблицы проще всего скопировать код из шаблона в Confluence и подставить нужные значения в определенные места с помощью функции format().

Сначала формируем хедер таблицы. После поочередно добавляем строки. Последней добавляем строку с тегами, закрывающими таблицу. Таким образом, мы сформируем html-код таблицы, который передадим в теле запроса.

Создание таблицы с помощью POST-запроса

Для создания таблицы с помощью запросов используем документацию Confluence REST API.

Для начала создадим в Confluence пустую страницу, которую будем использовать для нашего генератора таблиц. Так нам будет удобно отправлять запросы к странице с определенным id (пусть это будет 123456789), который можно посмотреть в адресе самой страницы https://***.ru/pages/viewpage.action?pageId=123456789

Для того чтобы сохранить новую таблицу, нам нужно узнать текущую версию страницы. Для этого используем GET запрос https://***.ru/rest/api/content/123456789?expand=version

Для работы с api используем RestAssured https://rest-assured.io/

И создадим метод для получения номера следующей версии страницы

/** * Получает версию таблицы в Confluence * * @param url адрес страницы * @param login логин от учетки Confluence * @param password пароль от учетки Confluence * @return номер следующей версии страницы */ public static int getNextPageVersion(String url, String login, String password) {    int result = RestAssured            .given()            .auth()            .preemptive()            .basic(login, password)            .get(url)            .jsonPath().get("version.number");     return result + 1; }

Для создания таблицы используем POST-запрос https://***.ru/rest/api/content/123456789/ с телом:

{     "body": {         "storage": {                         "value": "наш html код таблицы",             "representation": "storage"         }     },      "type": "page",     "title": "Генератор таблиц",      "version": {         "number": "100"         } }

Здесь мы указываем заголовок страницы, html-код самой таблицы и номер новой версии страницы. Так будет выглядеть метод:

/** * Создает таблицу в Confluence * * @param url адрес страницы * @param login логин от учетки Confluence * @param password пароль от учетки Confluence * @param table html код таблицы * @param title Название страницы * @param pageVersion Версия страницы */ public static void createConfluenceTable(String url, String login, String password, String table, String title, int pageVersion) {    String TABLE_BODY = "{\n" +            "    \"body\": {\n" +            "        \"storage\": {\n" +            "                        \"value\": \"%s\",\n" +            "            \"representation\": \"storage\"\n" +            "        }\n" +            "    },\n" +            "\n" +            "    \"type\": \"page\",\n" +            "    \"title\": \"%s\",\n" +            "\n" +            "    \"version\": {\n" +            "        \"number\": \"%s\"\n" +            "        }\n" +            "}";     RestAssured            .given()            .auth()            .preemptive()            .basic(login, password)            .header("Content-Type", "application/json")            .header("Connection", "keep-alive")            .body(format(TABLE_BODY, table, title, pageVersion))            .when()            .put(url)            .then()            .statusCode(200); }

И главный метод для выполнения программы:

import utils.RequestExecutor; import java.io.IOException; import java.util.Scanner;  import static utils.TableGenerator.createTableBody;  public class App {      public static void main(String[] args) throws IOException {          //Путь до папки с отчетом         String PATH = "C:\\Users\\User\\Desktop\\allure-report\\data\\test-cases";         //Название страницы в Confluence         String TITLE = "Генератор таблиц iOS";         //Название таблицы         String NAME = ": \"№1 Смоук 1.01\"";         //Ссылка на отчет в CI         String LINK = "Отчет в CI";         //Запрос для получения номера текущей версии страницы в Confluence         String URL_GET = "https://***.ru/rest/api/content/123456789?expand=version";         //Запрос для создания таблицы в Confluence         String URL_POST = "https://***.ru/rest/api/content/123456789/";          System.out.println("Для подключения к учетной записи Confluence");         Scanner in = new Scanner(System.in);          System.out.print("Введите логин: ");         String login = in.nextLine();          System.out.print("Введите пароль: ");         String password = in.nextLine();          RequestExecutor.createConfluenceTable(                 URL_POST,                 login,                 password,                 createTableBody(PATH, LINK, NAME),                 TITLE,                 RequestExecutor.getNextPageVersion(URL_GET, login, password)         );     } }

Заключение 

За счет того, что мы автоматизировали работу с отчетами, в нашем проекте удалось сделать тестирование быстрее и проще:

  • QA-специалисты смогли оперативно приступать к разбору отчетов, не затрачивая время на ручное создание таблиц и перенос данных из Allure-отчета.

  • Снизилась вероятность ошибок, которые могли возникнуть при ручном переносе данных из Allure-отчета в таблицу.

  • Работать с данными в таблице стало удобнее. 

В рамках проекта тестирование проводили на трех платформах: web, Android и iOS. Генератором таблиц первоначально пользовались только мобильные команды, при этом веб-команда уже к следующему регрессу оценила их опыт и тоже начала пользоваться предложенным методом.

Полный код к статье доступен на GitHub.

Спасибо за внимание! Надеемся, что наш опыт был вам полезен.


ссылка на оригинал статьи https://habr.com/ru/articles/585530/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *