Раздел 29 · Тестирование

Карантин и flaky-тесты: пожарная тревога, которая врёт

middle-senior~40 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Карантин и flaky-тесты: пожарная тревога, которая врёт

Сцена · пожарная тревога, которая врёт

В наборе кассы есть тест, который падает примерно раз в пять прогонов. Код не менялся, тест не менялся, но иногда красный. Первый раз ты вглядываешься, не находишь причины, перезапускаешь, и он зелёный. Второй раз просто перезапускаешь. К десятому разу ты, не глядя, жмёшь “retry” на любом красном CI.

Вот тут и кроется главная опасность. Flaky-тест опаснее, чем вообще отсутствие теста. Отсутствующий тест честно молчит. Flaky врёт: он орёт красным, когда всё в порядке, и команда привыкает игнорировать красное. А в тот день, когда покраснеет настоящий баг, его пролистают вместе с flaky. Пожарная сигнализация, которая срабатывает зря, кончается тем, что её отключают, и тогда пропускают настоящий пожар.

Карта урока · что заберёшь

  • поймёшь, почему flaky опаснее отсутствия теста и как он разрушает доверие;
  • разберёшь четыре источника flakiness: время, порядок, гонка, сеть;
  • освоишь карантин как срок на починку, а не как кладбище;
  • научишься искать корневую причину прогоном в цикле, а не глушить retry.

Раздел 1 · источники flakiness и карантин

Идея словами

Flaky не берётся из ниоткуда. Почти всегда это один из четырёх источников недетерминизма: время (waitForTimeout вместо ожидания состояния), порядок (тест опирается на данные соседа), гонка (два воркера пишут в одну строку), сеть (реальный вызов внешнего API). Пока источник не устранён, тест будет врать, сколько ни перезапускай.

Картинка · источник, карантин, починка

Виджет показывает один E2E “оплата проходит и баланс верный”. Выбери источник нестабильности и прогони десять раз: увидишь смесь зелёного и красного на одном и том же коде. Отправь в карантин: он перестанет блокировать мердж, но останется на глазах. Потом “почини причину” и прогони снова: десять из десяти зелёных, потому что устранён источник, а не добавлен retry.

e2e: оплата проходит и баланс верныйблокирует мердж

Причина: waitForTimeout(500): иногда сервер не успел ответить за 500 мс.

прогон ещё не запускали

Карантин убирает flaky из блокеров мерджа, но держит его на глазах с тикетом, чтобы чинили, а не удаляли. Зелёным набор делает не retry, а устранение источника: попробуй сначала прогнать flaky, потом «починить причину» и прогнать снова.

Шаг 1 · карантин это срок, а не кладбище

Когда тест flaky, у тебя три плохих и один хороший вариант. Плохие: удалить (потеряешь покрытие), игнорировать красное (отравишь весь набор), завернуть в retry (спрячешь баг под ковёр). Хороший: карантин.

Помеченный flaky уходит в отдельную группу, которая гоняется, видна, но не красит PR. На него заводят тикет с дедлайном. Карантин это срок на починку, а не кладбище: тест не удаляют (покрытие важно) и не глушат retry (баг важен), а держат на виду, пока не найдут причину.

Шаг 2 · карантин в CI

В пайплайне Kassa карантин это отдельная job с continue-on-error, которая гоняет помеченные тесты, но не блокирует мердж:

# .github/workflows/ci.yml
quarantine:
  needs: test
  runs-on: ubuntu-latest
  continue-on-error: true
  steps:
    - uses: actions/checkout@v4
    - run: pnpm install --frozen-lockfile
    - run: pnpm e2e:install
    - run: pnpm e2e --grep "@quarantine"

continue-on-error: true делает группу видимой (она появляется в списке проверок), но её краснота не валит PR. Помечаешь flaky-тест тегом @quarantine, он уезжает сюда. Блокирующие job (test, mutation, e2e без тега) остаются строгими.

Что взять с собой

  • flaky опаснее отсутствия теста: он учит команду игнорировать красное;
  • источников четыре: время, порядок, гонка, сеть;
  • карантин выводит flaky из блокеров, но держит на глазах с тикетом, не удаляя и не глуша retry.

дальше после входа

Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.

Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.