JavaRush /Курсы /Claude code /E2E, smoke и regression tests

E2E, smoke и regression tests

Claude code
19 уровень , 3 лекция
Открыта

1. Уровень теста и его роль — разные вещи

После выбора между unit, integration и API работа только начинается. Дальше нужно решить, нужен ли здесь полный пользовательский путь и какую роль тест сыграет в наборе. Когда разработчик впервые слышит рядом слова unit, integration, API, smoke, regression и E2E, возникает естественное желание сложить всё в одну коробку и подписать «виды тестов». Не складывайте. Тут две разные оси: на каком уровне вы проверяете систему и зачем.

Проще всего запомнить так: unit, integration, API и E2E — про глубину и границу проверки, а smoke и regression — про роль теста в наборе. Из-за этого один и тот же тест часто сидит на обеих осях сразу: короткий E2E оформления заказа заодно работает вашим smoke. А regression после бага с возвратом денег бывает и unit, и integration, и API, и E2E — зависит не от бага, а от того, где поломка ловится лучше всего.

Эту таблицу держите перед глазами, когда собираете test strategy для Commerce OS:

Ось Категория На какой вопрос отвечает Пример в Commerce OS
Level / scope
E2E
Проходит ли реальный путь пользователя целиком? оператор подтверждает возврат через интерфейс
Suite role
Smoke
Система вообще жива после изменения? сервис поднялся, список заказов открывается
Suite role
Regression
Не вернётся ли этот конкретный баг? повторный refund не создаёт дубликат

К оси level / scope относятся и unit, integration, API; здесь к ним добавлен самый широкий вариант, end-to-end path. Из этой таблицы хорошо видно главное: ни широкий охват, ни особая роль теста не означают «проверить всё подряд». Раздуете smoke до двадцати сценариев — он перестанет быть smoke. Напишете E2E на каждую кнопку — получите не страховку, а способ замедлить себе жизнь. Не появится regression после исправленного бага — команда надеется на память, настроение и фазу луны.

2. Smoke: датчик дыма, а не экспертиза здания

Smoke нужен не для полноты, а для быстрого сигнала, что система жива. Это датчик дыма, а не экспертиза здания: он показывает, что после свежего изменения всё не рассыпалось прямо на входе. В Commerce OS это ценно — сразу видно, что сервис поднимается, критичный endpoint отвечает, основной путь не умер.

Хороший smoke почти всегда короткий, быстрый и скучный. И это комплимент. Минута-полторы, один-два ключевых шага, понятный красный сигнал — задача выполнена. А smoke, который разворачивается в героический роман со входом, созданием заказа, промокодом, возвратом, письмом на почту и танцем в админке, — это попытка запихнуть весь проект в одну кнопку «проверить всё». Такие кнопки ломаются эффектно и бесполезно.

Простейший smoke для Commerce OS:

#!/usr/bin/env bash
set -euo pipefail
curl -fsS "$BASE/actuator/health" >/dev/null              # Бэкенд отвечает 200 OK
curl -fsS "$BASE/api/orders?page=0&size=1" >/dev/null    # Список заказов открывается
echo "Smoke ok"                                           # Smoke ok

Здесь нет красоты, зато есть смысл: приложение живо, просмотр заказов открывается. Если такой тест упал, дальше нет смысла рассуждать о тонких нюансах интерфейса — сначала верните системе пульс.

Очень полезно заранее решить, какие сценарии вообще достойны статуса smoke. В Commerce OS такими кандидатами обычно становятся проверка здоровья сервиса, открытие списка заказов, базовый просмотр очереди тикетов поддержки, получение ключевых метрик на дашборде. Их должно быть немного. Smoke — не каталог функций, а минимальный набор «сигналов жизни».

Именно здесь хорошо видно, почему Claude Code нельзя ставить на пьедестал с табличкой «сам знает, что тестировать». Он предложит каркас скрипта, напомнит про health-check, соберёт bash-файл по шаблонам проекта. Но критичный путь выбираете вы — только вы знаете, что важнее после конкретного изменения: список заказов, очередь возвратов или экран поддержки. Иначе получите «умный» smoke, который проверяет третьестепенную справку и игнорирует бизнес-риск.

3. Regression: вчерашняя боль как страховка

Regression — страховка от вчерашней боли, а не абстрактная проверка на будущее. Самый практичный и взрослый тип проверки: он не философствует про качество архитектуры, а задаёт один вопрос — возвращается ли конкретный баг, который уже случился с нами. Ответ «может быть» значит, что теста ещё нет или он слабый.

На практике regression лучше всего рождается из уже знакомого bugfix-цикла: сначала воспроизвели проблему, потом написали падающий тест, потом сделали минимальное исправление, потом убедились, что тест позеленел. В этом месте тест перестаёт быть абстрактной «проверкой на будущее» и становится зафиксированной памятью команды — не той, что живёт в головах и исчезает после отпуска, а той, что лежит в репозитории и честно ломает сборку, если баг решил вернуться.

Схема простая:

flowchart TD
    A[Нашли баг] --> B[Воспроизвели]
    B --> C[Написали падающий regression-тест]
    C --> D[Исправили проблему минимально]
    D --> E[Тест стал зелёным]
    E --> F[Баг не возвращается молча]

Представим, что в Commerce OS был неприятный баг: повторный запрос на возврат по одному и тому же заказу создавал две записи вместо одной. Если вы просто починили сервис и порадовались, это половина работы. Вторая половина — закрепить исправление тестом.

import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;

@Test
void repeatRefundDoesNotCreateDuplicateRecord() {
    refundService.request(orderId, requestId);
    refundService.request(orderId, requestId);
    assertEquals(1, refundRepository.countByOrderId(orderId)); // Дубликат не появился
}

Этот пример нарочно небольшой — и именно в этом его сила. Хороший regression обычно не пытается одновременно доказать всё на свете, он бьёт в одну конкретную боль, которая уже случилась, и дисциплинирует: заставляет сформулировать баг не как «что-то странное с refund», а как чёткое воспроизводимое поведение.

Здесь стоит помнить важный нюанс: regression — это не отдельный уровень тестирования. Он может быть unit, если баг жил в чистой бизнес-логике. Integration, если проблема на границе сервиса и базы. Даже E2E, если ошибка вылезала только в полном сценарии. Слово regression говорит не о глубине, а о роли: мы защищаемся от уже известной неприятности.

Именно поэтому regression редко бывает лишним. Если баг был реальным, болезненным и уже дошёл до пользователя, оставить его без теста — всё равно что закрыть дырку в окне газетой и надеяться, что зима не придёт. Оптимизм, конечно, вещь приятная, но репозиторий от него теплее не становится.

4. E2E: путь пользователя, а не кнопки

E2E кажутся очень заманчивыми, потому что похожи на настоящее пользовательское поведение. Нажали кнопку, открылась страница, выбрали заказ, подтвердили, увидели результат. После суховатых unit и integration это выглядит почти как кино: систему проверяют так, как ею пользуются в жизни. Но у этого кино дорогой продакшн: E2E медленнее, хрупче, требуют аккуратного выбора сценариев. Поэтому хороший инженер любит их без фанатизма.

Правило: E2E оставляйте для действительно критичных пользовательских путей — не для каждой сортировки, иконки и декоративной кнопки, а для сценариев, где сбой дорого обходится бизнесу или пользователю. В Commerce OS это оформление заказа, подтверждение возврата оператором, вход в админку, работа с критичным тикетом поддержки.

Смотрите на это как на таблицу решений:

Сценарий в Commerce OS Оставляем как E2E? Почему
Пользователь оформляет заказ Да Это прямой бизнес-критичный путь
Оператор подтверждает возврат Да Ошибка здесь бьёт по деньгам и поддержке
Сортировка списка заказов по колонке Скорее нет Часто достаточно API/integration-проверки
Цвет кнопки промокода Нет Это не E2E-задача, а вопрос UI-проверки
Переход по экрану метрик Иногда Только если экран критичен для операционного решения

Такой отбор очень отрезвляет: он не даёт превратить E2E-набор в музей пользовательских желаний. И это особенно важно для новичка, потому что после первого удачного Playwright-теста приходит опасная мысль: «сейчас я такими накрою всё». Накроете — но набор начнёт падать из-за анимаций, времени ответа, нестабильных селекторов. И команда станет относиться к красным E2E как к будильнику в субботу: раздражённо и без уважения.

Небольшой E2E для Commerce OS:

import { test, expect } from "@playwright/test";

test("оператор подтверждает возврат из очереди", async ({ page }) => {
  await page.goto("/support/refunds");
  await page.getByText("Заказ #1024").click();
  await page.getByRole("button", { name: "Подтвердить возврат" }).click();
  await expect(page.getByText("Возврат подтвержден")).toBeVisible(); // Оператор видит результат
});

Здесь хорошо то, что сценарий понятен даже без знания всего проекта, и если он упал — сразу ясно, какой путь сломался. А десятки E2E по пятнадцать шагов превращают падение в археологическую экспедицию: все идут смотреть, где именно умер этот динозавр.

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

5. Flaky: ложь чаще помощи

Flaky-тест разрушает доверие сильнее честного падения. Он то красный, то зелёный на одном и том же коде. Честный сломанный тест говорит: «У вас проблема». Flaky говорит: «Может, проблема, а может, нет, давайте погадаем». После нескольких таких эпизодов команда относится ко всему набору как к нервному родственнику: слушать надо, но верить без проверки опасно.

Источники flaky обычно довольно прозаичны: зависимость от текущего времени, случайных значений, нестабильной сети, порядка выполнения, медленных анимаций, внешних сервисов, слишком хрупких UI-селекторов. В E2E это частый гость — там больше движущихся частей. Но flaky заведётся и в regression, и в smoke, если завязать проверку на внешний сервис с переменным настроением.

Очень плохой и очень популярный анти-паттерн здесь называется «rerun until green»: тест красный, но мы не разбираемся, просто запускаем ещё раз. Позеленело со второй-третьей попытки — делаем вид, что жизнь прекрасна. На короткой дистанции это кажется удобным, на длинной — это способ накопить тихий хаос: нестабильный тест перестаёт быть тестом и превращается в лотерею.

В Workflow Kit такое фиксируйте прямо в проектных правилах:

## Политика flaky-тестов

- Не делаем «rerun until green».
- Если тест падает без изменения кода, сначала ищем источник нестабильности.
- Всё, что зависит от времени, сети и случайности, изолируем или фиксируем.

Это хороший пример того, как CLAUDE.md помогает не только писать код, но и держать инженерную дисциплину. Claude Code предложит исправить нестабильный селектор, заметит завязку на системное время, подскажет подменить внешний API контролируемой фикстурой. Но решение снова человеческое: признайте, что красный flaky — это не «почти зелёный», а полноценный риск.

Для Commerce OS особенно важно следить, чтобы широкие тесты не зависели от случайных факторов вроде реального платёжного провайдера, плавающей даты или нестабильной почты. Иначе получите странную ситуацию: E2E вроде проверяет возврат денег, а половина падений — из-за того, что тестовый провайдер ответил на секунду позже. Это уже не доказательство поведения, а погодная сводка.

6. Claude Code в широких проверках: не оракул

На широких проверках Claude Code особенно полезен как ускоритель рутинной части: набросает smoke-скрипт, каркас Playwright-теста, поможет выбрать точку для regression, разберёт лог упавшего E2E, объяснит, почему баг лучше страховать integration-тестом, а не браузерным сценарием. Но если дать ему слишком много свободы, он с той же лёгкостью напишет десять красивых и почти бесполезных тестов просто потому, что они легко генерируются.

Поэтому хорошая практика — сначала просить Claude помочь с дизайном, а не сразу с кодом. Например так:

Посмотри на текущий PR и TEST_STRATEGY.md.
Предложи:
1) один smoke-сценарий,
2) нужен ли здесь E2E,
3) какой regression-тест обязателен после фикса.
Код пока не пиши.

Такой запрос очень полезен, потому что удерживает правильный порядок мышления: сначала роль проверки, потом код. Иначе всё заканчивается привычной AI-магией — модель приносит Playwright на сорок строк, а вы потом гадаете, зачем он появился.

Claude особенно хорош ещё и в разборе уже случившихся падений. По логам объяснит, что smoke упал из-за неверного URL, а не бизнес-логики. Заметит, что regression ничего не доказывает, раз проходит и на старом поведении. Укажет, что E2E-сценарий слишком широкий и проверяет сразу три независимых пути. Но финальная работа остаётся за вами: прочитать лог, посмотреть screenshot, решить, должен ли сценарий вообще существовать и оправдывает ли он свою стоимость.

Широкие проверки берут ценой доверия, а не количеством. Smoke стоит держать коротким — минутный сигнал, что приложение живо. E2E оставлять на считанные критичные пути, где сбой бьёт по деньгам или пользователю. Regression заводить на каждый баг, который уже дошёл до прода, чтобы он не вернулся молча. А доверие к этому набору держится на одном: ни один тест в нём не должен быть flaky — иначе красный сигнал превращается в лотерею, и вся страховка обесценивается. Claude Code ускоряет сборку каждого из этих трёх типов, но роль и стоимость проверки выбираете вы. Дальше задача — не испортить эту страховку шумными данными, случайными граничными случаями и слабыми ассерциями.

1
Задача
Claude code, 19 уровень, 3 лекция
Недоступна
In-session классификация широких проверок
In-session классификация широких проверок
1
Задача
Claude code, 19 уровень, 3 лекция
Недоступна
Добавление regression-теста на duplicate discount
Добавление regression-теста на duplicate discount
Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ