Allure-аннотации в скриптах Mockarty
Нагрузочный и функциональный раннеры Mockarty умеют выгружать результаты
в формате Allure 2 — том же, что используют
allure-pytest, allure-java, allure-junit5 и экосистема k6-allure.
Это значит, что бизнес и QA-руководители получают богатый HTML-отчёт со
шагами, вложениями, параметрами и деревом feature → story → epic — прямо
из ваших обычных скриптов.
Это руководство — пользовательский справочник по API аннотаций,
который вы добавляете в скрипты на JavaScript / Go / Python / Java, чтобы
сделать отчёт информативным. Аннотации необязательны — без них вы всё
равно получаете корректный, минимальный отчёт с pass/fail и длительностью.
Когда нужны Allure-аннотации
- Скрипты гоняются в CI и хочется более богатого артефакта, чем
JUnit XML. - Идёт миграция с
k6 + allure-k6— нужна замена «один-в-один». - Стейкхолдеры (PM, QA-лиды) читают HTML-отчёт и хотят навигацию по
Feature / Story / Owner, а не по сырым URL. - К прогонам прикладываются артефакты (скриншоты, payload’ы, заголовки),
которые неудобно открывать из JSON-файла.
Быстрый пример (JavaScript / k6-совместимый)
В нагрузочном скрипте Mockarty глобал allure инжектится
автоматически. Также его можно импортировать явно из mockarty/allure
(путь k6/allure принимается как алиас) — ради
переносимости скриптов.
import http from 'k6/http';
import { check } from 'k6';
// 'allure' — глобал; либо импорт: import { allure } from 'mockarty/allure'
export const options = { vus: 10, duration: '30s' };
export default function () {
allure.feature('Checkout');
allure.story('Apply discount code');
allure.severity('critical');
allure.owner('payments-team');
allure.tag('regression');
allure.tmsLink('JIRA-1234', 'Apply discount');
allure.parameter('region', 'eu-west-1');
allure.step('login', () => {
const r = http.post('https://api.example.com/login', { user: 'alice' });
check(r, { 'login 200': (res) => res.status === 200 });
});
allure.step('apply discount', () => {
const r = http.post('https://api.example.com/cart/discount',
JSON.stringify({ code: 'SAVE10' }),
{ headers: { 'Content-Type': 'application/json' }});
allure.attach('response body', r.body, 'application/json');
check(r, { 'discount 200': (res) => res.status === 200 });
});
}
Запуск с Allure-репортером (--allure-results-dir или переменная
окружения ALLURE_RESULTS_DIR):
mockarty-cli perf run script.js --reporter allure --allure-results-dir ./results
allure generate ./results --clean -o ./report
allure generate — это сторонний Allure CLI; Mockarty генерирует
совместимые *-result.json, поэтому любая версия Allure, понимающая
формат 2, отрисует ваш отчёт.
Справочник аннотаций
API повторяет allure-pytest / allure-js. Имена совпадают — документация
этих экосистем тоже подойдёт.
Шаги
allure.step('descriptive name', () => {
// всё, что внутри — HTTP-вызовы, asserts, etc. — атрибутируется
// на этот шаг, со start/stop. Шаги вкладываются.
});
Если коллбек бросает — шаг помечается failed; если бросает неожиданный
тип ошибки (опечатка, ReferenceError) — broken. Шаги могут вкладываться
любой глубины; отчёт отрисует дерево.
Вложения (attachments)
allure.attach('payload.json', body, 'application/json');
allure.attach('screenshot.png', pngBytes, 'image/png');
- Первый аргумент — display-имя в отчёте.
- Второй — содержимое (string, ArrayBuffer, Uint8Array).
- Третий — MIME; отчёт по нему выбирает viewer (JSON-prettyprinter,
image-renderer, plain-text fallback).
Вложения пишутся рядом с JSON-результатом, в JSON хранится только имя
файла. Writer пишет большие вложения потоком; в памяти ограничения нет
сверх того, что разрешает JS-куча, но для многомегабайтных payload’ов
лучше делать сэмплинг.
Иерархические labels
allure.epic('Billing');
allure.feature('Checkout');
allure.story('Apply discount code');
allure.suite('payments-suite');
allure.parentSuite('e2e');
allure.subSuite('eu-region');
Управляют левым деревом навигации в отчёте (Behaviors, Suites).
Метаданные
allure.severity('critical'); // blocker | critical | normal | minor | trivial
allure.owner('payments-team');
allure.tag('regression');
allure.label('framework', 'mockarty'); // свободный k/v
Severity красит строку. Owner — чип. Тэги — фильтрация. Свободный
label(key, value) позволяет проставить что угодно (host, build number,
регион) без плагина.
Title и description
allure.title('Checkout: apply discount code to a 50€ cart');
allure.description('Verifies the SAVE10 promo at the EU pricing tier.');
title — display-имя теста в отчёте. description принимает plain text
или Markdown (HTML-отчёт санитизирует).
Ссылки
allure.link('https://example.com', 'docs', 'link');
allure.issue('JIRA-1234'); // type: issue
allure.tmsLink('TC-456', 'TestRail TC-456'); // type: tms
type маппится на стиль ссылки в Allure (issue / tms / link). Без
name отображается URL.
Параметры
allure.parameter('region', 'eu-west-1');
allure.parameter('vu', '10');
Параметры идут в шапку теста. Allure группирует параметризованные кейсы:
один тест с разными параметрами становится одной строкой с N подзапусками.
Динамические правки
Пространство allure.dynamic.* позволяет задавать значения изнутри
шага (например, после вычисления). Набор методов — тот же:
allure.step('measure', () => {
const lat = measureLatency();
allure.dynamic.parameter('latency_ms', String(lat));
allure.dynamic.severity(lat > 1000 ? 'critical' : 'normal');
});
Схема Allure-результата (wire-формат)
Mockarty пишет <uuid>-result.json в формате Allure 2. Ключевые поля:
| Поле | Тип | Назначение |
|---|---|---|
uuid |
string | Идентичность результата; случайный на запуск. |
historyId |
string | Стабильный между запусками; используется для history-sparkline. |
testCaseId |
string | Опциональный стабильный id тест-кейса. |
fullName |
string | Полное имя (например, script.js#checkout). |
name |
string | Display-имя; allure.title() или авто-derived из скрипта. |
description |
string | Markdown / plain text. |
descriptionHtml |
string | Заранее отрендеренный HTML (Mockarty не заполняет; зарезервировано). |
status |
enum | passed / failed / broken / skipped. |
statusDetails |
object | { message, trace, known, muted, flaky } для failed/broken. |
stage |
enum | Всегда finished в Mockarty (другие — для live-update). |
start/stop |
int64 | Unix-millis timestamps. |
labels |
array | [{ name, value }, …] — feature/story/epic/severity/owner/tag/… |
links |
array | [{ name, url, type }, …] |
parameters |
array | [{ name, value }, …] |
steps |
array | Дерево шагов; у каждого свой status/start/stop. |
attachments |
array | [{ name, source, type }, …] — source — имя файла на диске. |
Коллекции (labels, links, parameters, steps, attachments) всегда
сериализуются как [], а не null — ради совместимости с
allure-pytest. Это то, что позволяет интерлевать Go / JS / Python
результаты в одном отчёте.
Канонические имена labels
Отчёт рендерит эти labels с first-class чипами и навигацией; всё
остальное идёт в общую вкладку «labels»:
feature · story · epic · severity · owner · tag ·
suite · parentSuite · subSuite · host · thread ·
framework · language · package · testClass · testMethod ·
AS_ID.
Канонические типы ссылок
issue · tms · link (универсальный).
SDK-примеры
Та же поверхность доступна в SDK на разных языках. Каждый SDK пишет
Allure-JSON локально — RTT к серверу не нужен.
Go
import (
"context"
"github.com/mockarty/mockarty-go/allure"
)
func TestCheckout(t *testing.T) {
ctx, scope := allure.NewScope(context.Background(),
allure.WithFeature("Checkout"),
allure.WithStory("Apply discount"),
allure.WithSeverity(allure.SeverityCritical),
)
defer scope.Finish()
scope.Step("login", func(ctx context.Context) error {
// … HTTP-вызов …
return nil
})
scope.Step("apply discount", func(ctx context.Context) error {
body := []byte(`{"code":"SAVE10"}`)
scope.Attach("payload.json", "application/json", body)
return nil
})
}
Python
import allure # из Mockarty Python SDK
@allure.feature("Checkout")
@allure.story("Apply discount")
@allure.severity("critical")
def test_checkout():
with allure.step("login"):
# HTTP-вызов
pass
with allure.step("apply discount"):
body = b'{"code":"SAVE10"}'
allure.attach(body, name="payload.json", attachment_type=allure.MIME.JSON)
Java
import ru.mockarty.allure.Allure;
@Test
@AllureFeature("Checkout")
@AllureStory("Apply discount")
@AllureSeverity("critical")
void checkout() {
Allure.step("login", () -> { /* HTTP-вызов */ });
Allure.step("apply discount", () -> {
Allure.attach("payload.json", "application/json",
"{\"code\":\"SAVE10\"}".getBytes());
});
}
Имена API в Java- и Python-SDK выровнены с официальными allure-junit5 /
allure-pytest — существующие команды могут копировать привычные паттерны.
Интеграция с CLI
Allure-репортер принимается любой run-командой CLI:
mockarty-cli perf run script.js --reporter allure --allure-results-dir ./results
mockarty-cli test run flow.mockarty.json --reporter cli,allure:./results
mockarty-cli perf run script.js --reporter allure --allure-results-dir ./results
Несколько репортеров одновременно:
mockarty-cli perf run script.js \
--reporter cli \
--reporter json:./report.json \
--reporter junit:./junit.xml \
--reporter allure --allure-results-dir ./allure-results
После завершения:
allure generate ./allure-results --clean -o ./report
allure open ./report # открывает локальный браузер
allure — сторонний CLI; ставится со страницы
allurereport.org/docs/install/.
Любая версия, понимающая формат 2 (>= 2.13), отрисует артефакты
Mockarty.
Выборочный прогон (тест-планы)
Тест-план — небольшой JSON-файл со списком тестов, которые нужно
запустить. Именно так работает «перезапустить только упавшие»: вы получаете
план, указываете на него ALLURE_TESTPLAN_PATH — и SDK прогоняет только то,
что в плане перечислено.
Mockarty умеет строить планы сам:
# Только упавшие / сломанные кейсы завершённого запуска
mockarty-cli allure rerun-failed --launch <launch-id> --out ./testplan.json
# Только тесты, затронутые изменением кода
mockarty-cli util ci impact --base origin/main --head HEAD \
--namespace my-team --allure-out ./testplan.json
Дальше запускайте набор с выставленной переменной:
export ALLURE_TESTPLAN_PATH=$PWD/testplan.json
pytest tests/ # Python
./gradlew test # Java (JUnit 5)
go test ./... # Go
Файл читают все три SDK — Go, Python и Java. Никаких дополнительных флагов и
настроек: pytest-плагин, JUnit 5-расширение и Go-пакет allure включаются
самим фактом подключения зависимости.
Формат файла
{
"version": "1.0",
"tests": [
{"id": 11111, "selector": "my.company.SimpleTest.simpleTestOne"},
{"selector": "tests/auth/test_login.py::test_ok"},
{"id": "CASE-9"}
]
}
В каждой записи должен быть id, selector или оба. Тест запускается, если
совпало любое из них:
id— Allure-идентификатор теста:@allure.id("777")в Python,
@AllureId("777")в Java,allure.WithAllureID("777")в Go. Собственные
привязки Mockarty тоже подходят —@mockarty.testing.test_case("CASE-9")и
@TestCase("CASE-9"), — поэтому набор на «чистом» Mockarty адресуется по
идентификатору тест-кейса без Allure-аннотаций.selector— уникальное имя теста. Каждый SDK принимает несколько
эквивалентных написаний, чтобы совпал план от любого инструмента:Язык Какие селекторы принимаются Python tests/auth/test_login.py::TestLogin::test_ok, то же без суффикса[param],tests.auth.test_login.TestLogin#test_ok,tests.auth.test_login.TestLogin.test_okJava уникальный id JUnit, com.acme.LoginTest#shouldLogIn,com.acme.LoginTest#shouldLogIn(java.lang.String),com.acme.LoginTest.shouldLogIn,LoginTest#shouldLogInGo TestLogin/happy,example.com/pkg::TestLogin/happy,example.com/pkg.TestLogin/happy,TestLogin#happy
Что происходит в каждой ситуации
| Ситуация | Что делает SDK |
|---|---|
ALLURE_TESTPLAN_PATH не задана |
Ничего не меняется — идёт обычный полный прогон. |
| В плане N тестов | Запускаются только они, остальные пропускаются. |
| В плане есть тесты, но ни один не совпал | Не выполняется ничего, и это явно помечается — прогон не считается обычным успехом. |
План пустой ("tests": []) |
Не выполняется ничего, прогон считается неуспешным. Пустой план означает «не выбрано ни одного теста», и зелёная галочка тут была бы обманом. |
| Файла нет, он не читается или это не валидный JSON | Прогон останавливается с явной ошибкой. Молчаливого отката к полному прогону не происходит. |
MOCKARTY_TESTPLAN_MODE=off |
План игнорируется, идёт полный прогон — сознательный аварийный выход. |
Две строки про отказ — и есть смысл всей механики. Попросить 3 теста и
получить прогон 3000 — или зелёную сборку, в которой не выполнилось ни
одного, — это потраченное время CI и спрятанные падения, поэтому SDK
отказываются и от того, и от другого.
Конкретно:
| Язык | Пустой план ("tests": []) |
План ни с чем не совпал | Битый или отсутствующий план |
|---|---|---|---|
| Python | все тесты снимаются с прогона; pytest завершается кодом 5 («no tests ran») и пишет причину |
то же — pytest завершается кодом 5 и пишет причину |
pytest завершается кодом 4 (ошибка использования) ещё до сбора тестов |
| Go | все тесты пропускаются; allure.TestMain возвращает 5 и пишет причину |
то же — allure.TestMain возвращает 5 |
тест падает с указанием причины, allure.TestMain возвращает 4 |
| Java | discovery останавливается с сообщением, что план ничего не выбрал — сборка падает | выполняется ноль тестов, причина печатается; сделать это падением сборки можно через test { failOnNoDiscoveredTests = true } в Gradle или <failIfNoTests>true</failIfNoTests> в Surefire |
discovery останавливается с ошибкой чтения/разбора — сборка падает |
Java — единственное место, где «план ни с чем не совпал» сам по себе не роняет
сборку: JUnit Platform не даёт адаптеру способа завалить прогон после discovery,
поэтому SDK печатает причину и оставляет вердикт переключателю «нет обнаруженных
тестов» в сборочном инструменте. Пустой план роняет сборку — это состояние видно
уже во время фильтрации.
В Go эти коды возвращает allure.TestMain, поэтому подключите его один раз
на пакет:
func TestMain(m *testing.M) { os.Exit(allure.TestMain(m)) }
Без него невыбранные тесты всё равно корректно пропускаются, но go test
напишет привычное ok для прогона, в котором ничего не выполнилось.
Java дополнительно принимает системные свойства вместо переменных окружения —
-Dallure.testplan.path=... и -Dmockarty.testplan.mode=off, — их часто
удобнее задавать из Gradle или Maven. Если заданы оба источника, побеждает
переменная окружения.
Примечания
- Тест-план — дополнительный фильтр. Он складывается с обычным отбором
(pytest -k,--testsв Gradle,go test -run): тест запустится, только
если прошёл оба. - Если рядом с плагином Mockarty установлен официальный пакет
allure-pytest,
он читает тот же файл и применяет свой фильтр первым. Он понимает только
своё написание селектораpackage.Class#test— поэтому при таком сочетании
надёжнее планы сidлибо с селекторами именно в этой форме. - В Go фильтруются тесты, проходящие через
allure.T(t, ...). Если набору
нужен только отбор без отчётности Allure — поставьте первой строкой теста
allure.SkipIfNotSelected(t).
Загрузка в Mockarty (Окружение, Категории, Исполнитель)
При выгрузке результатов в Mockarty (mockarty-cli allure upload ./allure-results
или mockarty-cli allure watch -- <команда>) обрабатываются и файлы уровня
запуска, которые адаптеры Allure кладут рядом с *-result.json:
| Файл | Что делает Mockarty |
|---|---|
environment.properties / environment.xml |
Разбирается в панель «Окружение» (ключ/значение) на вкладке Overview отчёта. |
categories.json |
Применяется как классификатор дефектов — упавшие результаты раскладываются по корзинам (например «Product defects» / «Test defects») и показываются на вкладке Категории. |
executor.json |
Показывается карточкой Исполнитель (имя сборки + ссылка) на вкладке Overview. |
Эти файлы относятся ко всему запуску (а не к одному тесту), поэтому
выгружаются только при активном launch — сначала создайте его:
eval "$(mockarty-cli allure launch create --launch-name "nightly $(date +%F)")"
mockarty-cli allure upload ./allure-results # результаты + environment/categories/executor
mockarty-cli allure launch close
launch close завершает launch тем итогом, который Mockarty выводит из
реально пришедших результатов:
| Что пришло | Записанный статус launch |
|---|---|
| все результаты прошли (или пропущены) | completed |
| хотя бы один результат упал | failed |
| результатов нет вообще | failed — ничего не выгружено, значит launch не зелёный |
Если пайплайн действительно прервали — скажите об этом явно:
mockarty-cli allure launch close --abort # запишет launch как cancelled
Команда печатает записанный вердикт, чтобы в логе CI было видно, чем всё
закончилось:
LAUNCH_CLOSED=8d0c9b2e-... status=completed results=42 failed=0
environment.properties принимает и форму Java .properties
(строки ключ=значение, комментарии #), и форму XML
<environment><parameter> — Mockarty определяет её автоматически.
categories.json использует стандартную схему Allure: массив правил
{name, matchedStatuses, messageRegex, traceRegex}, применяемых к упавшим
результатам по принципу «первое подходящее правило».
Диагностика
| Симптом | Причина / решение |
|---|---|
| Отчёт пуст / “No results found” | Папка allure-results пустая. Сверьте путь --allure-results-dir с входом allure generate. |
| Шаги не вложены | Забыли передать callback в allure.step — форма без callback’а считается ошибкой. |
| Attachment отображается как бинарь | Не указан или указан неверный MIME. Передавайте application/json, image/png и т.д. явно. |
| Один и тот же тест появляется дважды | Два скрипта эмиттят одинаковый historyId. Либо allure.label('AS_ID', '<unique>'), либо меняйте имя скрипта. |
Чипы feature / severity пустые |
Label задан на шаге, а не на тесте. Вынесите за пределы allure.step(…). |
| Отчёт рендерится, но labels не появляются в дереве | В папке остались старые прогоны. allure generate --clean сбросит их. |