Как писать багрепорт, который примут: структура, шаги и частые ошибки
Багрепорт пишут не для отчётности. Его читает человек, которому предстоит воспроизвести дефект у себя, понять, насколько всё плохо, и решить, чинить сейчас или после релиза. Если отчёт этого не даёт, он возвращается с вопросами — и время теряют оба.
Из чего состоит отчёт
Минимальный рабочий набор одинаков почти везде: заголовок, окружение, шаги воспроизведения, ожидаемый результат, фактический результат. Дальше добавляют важность, вложения, логи — но без первых пяти пунктов отчёта нет.
Проверить себя просто: отдай отчёт человеку, который ничего не знает о задаче. Если он повторил дефект, не задав ни одного вопроса, — отчёт готов.
Заголовок: что сломалось и где
Заголовок читают в списке из сотни строк, и по нему решают, открывать ли. Поэтому в нём должно быть два факта: что именно происходит и в каком месте. «Не работает корзина» не содержит ни одного из них.
Хороший заголовок переживает сокращение до одной строки в списке и всё ещё понятен. Плохой требует открыть отчёт, чтобы понять, о чём он.
✕
Ошибка в заказе
✓
POST /orders создаёт заказ при пустой корзине и возвращает 201
Шаги воспроизведения: точные данные, а не пересказ
Шаг — это действие, которое можно повторить буквально. «Отправить некорректное значение» повторить нельзя: некорректных значений бесконечно много, и половина из них работает правильно. Нужно то самое значение, на котором сломалось.
Для API это означает: метод, полный адрес с параметрами, тело запроса и заголовки, если они влияют. Для интерфейса — что нажали и что ввели, дословно. Порядок шагов важен: дефект, который воспроизводится только после входа в аккаунт, без этого шага не повторится.
✕
1. Открыть каталог 2. Поставить странный фильтр 3. Ничего не отфильтровалось
✓
1. GET /products?min_price=-500 2. Смотрим код ответа и число позиций в data
Ожидаемый результат берётся из требований
Самая частая слабость отчёта — ожидаемый результат, придуманный на месте. «Ожидается, что так быть не должно» — это не требование, а мнение, и спорить с ним можно бесконечно.
Ожидаемый результат — это цитата: строка из требований, критерий приёмки, пункт документации, поведение соседнего метода, который сделан правильно. Если сослаться не на что, это ещё не дефект, а вопрос к аналитику — и так его и стоит завести.
Фактический результат, наоборот, пишется без интерпретаций: код ответа, тело, конкретное число. Не «сумма посчиталась неправильно», а «в ответе total = 1380 при двух позициях по 690 и промокоде −10%».
Пять ошибок, из-за которых отчёт возвращают
- Два дефекта в одном отчёте. Починят один, закроют весь — второй уедет в релиз.
- Шаги по памяти. Написано одно, отправлено другое, воспроизвести не получается.
- Оценка вместо факта: «всё сломалось», «работает ужасно». Непонятно, что именно чинить.
- Нет окружения. На каком стенде, под каким пользователем, с какими правами.
- Дубликат. Прежде чем заводить, стоит поискать — на доске такой отчёт часто уже есть.
Полный пример API-багрепорта
Ниже — не универсальная форма, а рабочий пример. Он связывает наблюдение с контрактом и оставляет разработчику точный запрос, а не пересказ из памяти.
Заголовок: POST /orders создаёт заказ при пустой корзине и возвращает 201\nОкружение: QA, build 2026.09.21-3, user qa-buyer-17\nПредусловие: корзина пользователя пуста\n\nШаги:\n1. Отправить POST /api/v1/orders с валидным Bearer token\n2. Тело запроса: {}\n3. Выполнить GET /api/v1/orders\n\nОжидаемо: 422, order не создан (AC-ORD-04)\nФактически: 201; создан order_id=8412, total=0\nПовторяемость: 3/3\nДоказательства: request/response HAR, correlation_id=7af2…
Не вставляй рабочий токен, пароль, персональные данные или полный production-дамп. Секреты заменяют маской, персональные данные — синтетическими значениями, а доступ к чувствительным логам дают по принятому security-процессу.
Чек-лист перед отправкой и ретестом
Severity описывает ущерб, priority — очерёдность исправления для бизнеса. Их шкалы и владельцы зависят от команды, поэтому важнее обоснование. После статуса Fixed QA повторяет исходные шаги на указанной сборке и проверяет близкий риск, а не закрывает задачу по комментарию разработчика.
- В заголовке есть действие, неверный результат и место дефекта.
- Указаны build, окружение, роль, предусловия и точные тестовые данные.
- Expected ссылается на критерий, контракт или согласованное решение.
- Actual содержит наблюдаемые факты: статус, значения, время, id и частоту.
- Вложения открываются, секреты скрыты, а один отчёт описывает один дефект.
- При ретесте проверены исходный сценарий, исправленная сборка и ближайшая регрессия.
Разбор: баг появляется только у второго менеджера
Представь CRM: менеджер A создал клиента, а менеджер B открыл карточку по прямой ссылке. Твоя цель — написать отчёт, по которому разработчик воспроизведёт проблему, а команда поймёт риск. Одной фразы «чужой клиент виден» недостаточно: она не говорит, где сломана граница доступа.
- Зафиксировать правило доступа и источник ожидания.
- Подготовить два аккаунта и объект с известным владельцем.
- Повторить через UI и прямой API-запрос.
- Сохранить безопасные доказательства и определить влияние.
Отдели требование от предположения
Найди в задаче формулировку «менеджер видит только назначенных клиентов». Если такой нормы нет, сначала уточни у product owner, является ли распределение клиентов ограничением доступа или лишь фильтром по умолчанию. Не выдавай собственное понимание процесса продаж за согласованный контракт. В отчёте приведи номер критерия и версию спецификации; ссылка на документ полезнее общего «по требованиям не должно».
Сделай воспроизведение независимым от автора
Заведи синтетических пользователей A и B одной роли и тестового клиента, назначенного A. Укажи build, окружение, id клиента, способ назначения и точный URL или метод API. Сначала проверь позитивный контроль: A видит карточку. Затем B запрашивает тот же id. Так исключается ложный вывод, что карточка просто публична по бизнес-правилу или что объект вообще недоступен.
Докажи нарушение на границе системы
Скрытая ссылка в списке не является достаточной защитой. Скопируй запрос GET клиента из Network и повтори его с сессией B; отдельно проверь PATCH только в разрешённом тестовом окружении. Запиши статус, безопасный фрагмент ответа и факт изменения данных. Если API отдаёт 403, а UI показывает старую карточку из кеша, это другой дефект: сформулируй его отдельно, не смешивая два механизма.
Приоритизируй и перепроверь
Утечка чужих контактных данных потенциально серьёзнее косметики, даже если встречается редко. Передай находку по принятому security-каналу, не прикладывай реальные данные клиента в общий трекер. После исправления повтори исходный запрос, пару обратных ролей, прямой URL, список и экспорт: патч одного endpoint не обязательно закрывает тот же доступ в другом. Запиши build исправления и точный объём повторной проверки.
Title: Manager B reads client assigned to manager A via GET /clients/481\nEnvironment: QA, build 1842; synthetic A and B, same manager role\nExpected: B receives 403/404 per ACL-07; no client fields returned\nActual: B receives 200 and client name/email; reproduced 3/3\nEvidence: redacted request/response + correlation_id; no live PII\nScope: GET confirmed; PATCH, list and export require separate checks
Что считается сильным результатом?
Другой член команды может воспроизвести проблему без уточнений, видит источник ожидания и не получает чувствительные данные во вложении. В отчёте разделены подтверждённые факты и гипотезы о соседних endpoint. После исправления есть запись о ретесте именно того build, где патч был развёрнут.
Второй кейс: нестабильный баг без точного воспроизведения
Оплата иногда зависает после подтверждения заказа: один раз из двадцати, а повторить по инструкции не получается. Это не повод выбросить находку и не основание назвать её “критическим багом платежей” без доказательств. Нужен другой формат отчёта: наблюдение, частота, контекст и способ собрать недостающие данные.
Сохрани наблюдение до экспериментов
Запиши точное время и часовой пояс, build, браузер, account, order id, сумму и correlation id. Сохрани HAR или Network request/response, но вырежи cookies, токены и персональные данные. Отметь, что пользователь видел на экране, сколько длилось ожидание и был ли фактический платёж. Слова “подвисло” недостаточно: spinner на 12 секунд и 504 при списании денег — разные инциденты.
Измерь частоту честно
Серия из двадцати попыток с одним сбоем даёт наблюдение 1/20, а не доказанную вероятность 5%. Укажи число и условия прогонов, успешные тоже сохрани. Не запускай платежи на боевых картах и не используй общий пользовательский аккаунт: накопленная корзина и лимиты изменят результат. Если сбой связан с нагрузкой, отдельные тесты при низкой и высокой параллельности помогут выделить фактор.
Отдели симптом от гипотезы о причине
В отчёте факт: запрос вернул 504, но в истории появился оплаченный заказ. Гипотеза: ответ потерялся между сервисами. Не ставь “ошибка в очереди” в заголовок, пока логи этого не подтверждают. Сравни успешный и неуспешный trace, время ответа зависимостей и повторную доставку события; приложи ссылки на внутренние логи в разрешённом канале.
Опиши ожидаемое поведение на неопределённом исходе
Если клиент получил timeout после отправки платежа, он не знает, был ли платёж проведён. Согласованный контракт должен позволять безопасно запросить статус или повторить команду с тем же idempotency key без двойного списания. В отчёте укажи, какой именно инвариант нарушен: состояние заказа расходится с балансом, UI предлагает повторить оплату без проверки статуса или второй запрос создаёт дубль.
Планируй ретест и наблюдение
После исправления повтори исходные данные и факторы, которые повышали частоту сбоя; оцени не только зелёный UI, но и число платежей, журнал операций и итоговый статус. Если ошибка не поймана за 20 повторов, это не математическое доказательство исправления. Запиши объём прогона, мониторинг на проде и критерий, по которому команда считает риск приемлемым.
Observed: checkout timeout at 14:03:27 UTC, HTTP 504\nOrder 8412: paid after timeout; UI still shows Pay\nFrequency: 1 failure / 20 attempts on QA build 1842\nEvidence: redacted HAR, correlation_id=7af2, payment ledger id\nHypothesis: response lost after successful charge (unconfirmed)\nRisk: user may retry and trigger a second charge\nNext: compare traces; replay with same idempotency key
Когда заводить такой дефект?
Когда есть наблюдаемое отклонение и значимый риск, даже если точная последовательность не воспроизводится каждый раз. Отчёт должен честно обозначать частоту, доказательства, гипотезы и ограничения. Если отклонение пока не подтверждено, создай investigation item с тем же набором фактов, а не уверенный багрепорт с придуманной причиной.
Частые вопросы о багрепортах
Нужно ли заводить баг, если дефект воспроизвёлся один раз?
Да, если влияние существенно и есть доказательства. Укажи частоту, точное время, данные и логи, не обещая стабильной воспроизводимости. Один редкий дефект оплаты важнее стабильно кривого отступа.
Кто выставляет severity и priority?
Универсального правила нет. Часто QA предлагает severity, а product или triage определяет priority, но процесс команды может быть другим. Важны единые определения и записанное обоснование.
Что делать, если требования нет?
Зафиксировать наблюдаемое поведение и риск как вопрос или discovery-задачу, получить решение владельца продукта и только после этого записать ожидаемый результат. Личное предпочтение не становится дефектом автоматически.
Отчёт — рабочий документ, и научиться его писать можно только написав несколько десятков: на реальном дефекте, а не на выдуманном примере.