Интеграция с системами отчётов

Механизм отчётов служит для представления результатов тестирования в презентационной форме. Он позволяет создавать пользовательские интеграции с инструментами построения отчётов (например Allure Report или ReportPortal), TMS, системами логирования или отправлять информацию о прохождении тестов через телекоммуникационные средства связи.

Вместе с дистрибутивом поставляется расширения console и allure добавляющие возможность выводить информацию о тестировании на консоль и интегрировать тесты с инструментом Allure Report.

Для описания собственного расширения отчётов необходимо создать расширение в каталоге extensions. В нём нужно поместить описание класса отчёта который должен наследоваться от класса BaseReport.

BaseReport

В классе отчёта можно переопределить следующие методы:

Метод Событие
start Запуск теста
start_step Переход на новый шаг
stop_step Завершение шага
sub_test Запуск субтеста
message Вывод сообщения
error Вывод сообщения об ошибке (в инфраструктуры или платформы)
warning Вывод сообщения с предупреждением
action Выполнение команды (работает на любом действии в том числе и с ошибкой)
test_error Ошибка теста FAIL
fatal_error Ошибка теста FATAL
timeout_error Превышение времени выполнения теста
skip_test Пропуск теста
stop_test Остановка теста
close Завершение всех тестов

Каждый из этих методов будет вызван при наступлении соответствующего события. Все методы кроме close принимают данные о состоянии прохождения теста в виде экземпляра класса ReportData.

ReportData

Объект класса ReportData предоставляет информацию о выполнении текущего действия (т.е. команды с параметрами) и содержит следующие атрибуты:

Метод Тип данных Описание
action_name str Наименование текущего действия
arguments ([], {}) Позиционные и именованные аргументы для текущего действия
attempt int Количество перезапусков
browser_name str Название браузера
browser_version str Версия браузера
cookies dict Словарь cookies (только при ошибке)
debug [(str, str)] Список пар “идентификатор”, “значение” (определено в случае ошибки).
description str Описание теста или шага
device (str, str, str) Возвращает тройку (платформа, устройство/архитектура, имя_устройства)
file_line str Имя файла с исходным кодом теста и номер строки для текущего действия
is_parent bool Текущее действие выполняется в субтесте или субстепе
links dict Словарь ссылок с дополнительной информацией о тестировании
logs dict Словарь логов selenium-а (только для метода stop_test)
message str Текст сообщений
page_name str Заголовок текущей страницы (после выполнения команды)
page_source str Исходник страницы (только при ошибке)
parent_uuid str Идентификатор родительского теста или субтеста
repeated int Количество последовательных запусков
retries int Максимальное количество перезапусков
screenshot [(str, bytes)] Список пар: (“заголовок”, скриншот). Скриншиты в виде байт в формате png
script str Идентификатор текущего скрипта
script_args dict Аргументы текущего скрипта
status str Статус текущего действия
step_args dict Аргументы шага
step_parent_uuid str Идентификатор родительского шага
step_status str Статус текущего шага
step_time float Время выполнения текущего шага
step_title str Заголовок шага
step_uuid str Идентификатор шага
test_args dict Аргументы теста
test_id str Идентификатор теста
test_name str Наименование теста
test_parameters dict Параметры с которыми был запущен тест
test_scope dict Пространство имён теста
test_status str Статус теста
test_title str Заголовок теста
thread_id str Идентификатор потока в котором запущен тест
time float Длительность выполнения текущей команды
timeout float Тайм-аут для текущего действия
timestamp timestamp Время запуска теста
url str Адрес текущей страницы (после выполнения команды)
value str Значение возвращённое действием
warning [str] Текст предупреждений

Значение атрибута screenshot, cookies и page_source будет доступно только при вызове специальной команды или при возникновении ошибки.

Статусы действий и тестов

Для отслеживания состояния выполнения команд и тестов существуют статусы. Каждая команда завершается с тем или иным статусом. Если команда завершилась с ошибкой или предупреждением, то всему тесту будет присвоен соответствующий статус. Просмотреть статусы команд можно в режиме отладки.

Статусы тестов:

Статус Описание
UNKNOWN Тест не запускался
STARTED Тест был запущен, но не завершился
PASSED Тест успешно завершился
RETRO Тест успешно завершился, но не с первой попытки
WARNING Тест завершился с предупреждением
FAILED Произошла не критическая ошибка, тест продолжил работу
FATAL Тест был остановлен, произошла критическая ошибка
TIMEOUT Тест был остановлен, превышено максимальное время выполнения команды
ERROR Тест был остановлен, произошла системная ошибка в работе платформы или кода конфигурации
XFAILED Негативный тест завершился без ошибки
XPASSED Негативный тест завершился с ошибкой
SKIPPED Тест был пропущен командой SKIP_TEST
STOPPED Тест был остановлен командой STOP_TEST

Статусы шагов и команд:

Статус Описание
PASSED Команда успешно завершилась
SKIPPED Команда была пропущена
WARNING Статус теста был переведён в WARNING
FAILED Статус теста был переведён в FAILED
FATAL Статус теста был переведён в FATAL
TIMEOUT Статус теста был переведён в TIMEOUT
ERROR Статус теста был переведён в ERROR
SKIP_TEST Статус теста был переведён в SKIPPED
STOPPED Статус теста был переведён в STOPPED

Пример расширения отчёта

Ниже приведён пример простого расширения которое записывает в лог ход выполнения тестов:

#!/usr/bin/python3
# coding: utf-8

import os
import time

from report import BaseReport
from parameter import CONFIG, ItemConfig

ItemConfig.registrator(
    ItemConfig("TEXT_LOG_FILE", str, os.path.abspath("report.log"), "Путь к файлу лога")
)

class TextLog(BaseReport):
    def __init__(self):
        self._bufer     = {}
        self._log_file  = CONFIG.TEXT_LOG_FILE
        
        with open(self._log_file, "a") as log:
            log.write("%s\tSTART\t%s\n"%(str(time.time()), CONFIG.TEST_CASE_PATH))
    
    def _bufirezator(self, test_id, data):
        if not test_id in self._bufer:
            self._bufer[test_id] = []
        self._bufer[test_id].append(data)
    
    def start(self, report):
        if report.attempt > 0:
            title = "Перезапуск (%i/%i)" % (report.attempt, report.retries)
        if report.is_parent:
            title = "Субтест " + report.test_title
        else:
            title = "%s (%s)" % (report.test_title, report.browser_name)
        self._bufirezator(report.test_id, title)
        if report.test_description:
            self._bufirezator(report.test_id, report.test_description)
        if report.test_parameters:
            self._bufirezator(report.test_id, report.test_parameters)
    
    def start_step(self, report):
        self._bufirezator(report.test_id, "Запуск теста %s..." % report.step_title)
    
    def sub_test(self, report):
        self._bufirezator(report.test_id, "Запуск субтеста %s..." % report.message)
    
    def message(self, report):
        self._bufirezator(report.test_id, report.message)
    
    def error(self, report):
        self._bufirezator(report.test_id, "Ошибка в действии " + report.action_name)
    
    def warning(self, report):
        self._bufirezator(report.test_id, "Предупреждение: %s %s" % (report.action_name, report.warning))
    
    def test_error(self, report):
        self._bufirezator(report.test_id, "Ошибка в действии " + report.action_name)
    
    def fatal_error(self, report):
        self._bufirezator(report.test_id, "Фатальная ошибка в действии " + report.action_name)
    
    def timeout_error(self, report):
        self._bufirezator(report.test_id, "Превышение времени выполнения теста")
    
    def skip_test(self, report):
        self._bufirezator(report.test_id, "Тест пропущен!")
        self.stop_test(report)
    
    def stop_test(self, report):
        self._bufirezator(report.test_id, report.test_status)
        with open(self._log_file, "a") as log:
            for x in self._bufer.pop(report.test_id):
                log.write("\n"+x)
            log.write("\n\n")
    
    def close(self):
        with open(self._log_file, "a") as log:
            log.write("\nSTOP: %s"%str(time.time()))

Пользовательские атрибуты тестов

Если система отчётов оперирует данными которые не предусмотрены в стандартной модели описания теста, то их можно добавить через пользовательский атрибуты тестов. В методе отчёта их значение можно будет как значение соответствующего ключа в словаре test_args.

Например расширение report_allure добавляет следующие дополнительные атрибуты: epic, feature, story, issue, owner, tms_link.

Добавить пользовательский атрибут можно при помощи класса ItemTestConfig из модуля core_dsl.

ItemTestConfig(“name”, data_type, default [, description ] [, deserialize ] [, validator ])

Создаёт описание атрибута теста. Класс принимает следующие параметры:

Аргумент Описание
name Идентификатор параметра
data_type Тип данных
default Значение по умолчанию
description Краткое описание параметра По умолчанию - ““
deserialize Функция десериализатор По умолчанию - None
validator Функция валидатор По умолчанию - None

Параметр default может быть определён как функция. В этом случае ей будет перед запуском теста будет передаваться его объект.

Значение параметров deserialize и validator аналогично одноимённым параметров класса ItemConfig.

ItemTestConfig.registrator(описание параметра {описание параметра})

Регистрирует одно или несколько описаний атрибута теста.

Пример:

from core_dsl import ItemTestConfig

# Регистрируем атрибуты теста
ItemTestConfig.registrator(
    ItemTestConfig("owner",    str, "")
    , ItemTestConfig("tms_link", str, "")
)

# Теперь в тесте можно их определить
TEST["атрибуты"](
    ....
    , owner="admin"
    , tms_link="https://example.com/tms/123"
)

# И в объекте отчёта можно получить их значение

class Allure(BaseReport):
    def start(self, report):
        obj = TestResult(name=report.test_title, uuid=report.test_id, start=get_time(report))

        if report.test_args["owner"]:
            obj.labels.append(Label(name="owner", value=report.test_args["owner"]))

        if report.test_args["tms_link"]:
            obj.links.append(Link(LinkType.TEST_CASE, report.test_args["tms_link"]))

Для версии 1.1 редакция от 16.03.2026