сеньорчикОткрыть в Telegram
← вся теориятеория к собесу · Автоматизация тестирования

Надёжность автотестов

Надёжность автотестов

Посчитаем, что значит «почти стабильный набор». Пусть каждый тест мигает всего в 0,5% прогонов. Тогда набор из 50 тестов будет полностью зелёным в 78% случаев, из 200 - уже только в 37%, а из 1000 - в 0,7%. То есть при тысяче тестов и полупроценте нестабильности зелёный прогон вы увидите примерно раз в сто пятьдесят запусков.

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

// Формулировки: «что такое флаки-тест?», «откуда берётся нестабильность?», «что делать с мигающим тестом?».

Арифметика нестабильности

Флаки-тест (от английского flaky, «хлопьями осыпающийся») - это тест, который на одном и том же коде то падает, то проходит. Считают его частоту: сколько падений на сто прогонов при неизменном коде.

Почему даже крошечная частота смертельна, показывает счёт. Чтобы прогон был зелёным, должны пройти все тесты сразу, поэтому вероятности перемножаются. При нестабильности 0,5% на тест: 50 тестов - 78% зелёных прогонов, 200 - 37%, 1000 - 0,7%. Уменьшим нестабильность впятеро, до 0,1%: 1000 тестов дадут зелёный прогон в 37% случаев. Всё равно каждый второй прогон красный - и это при почти идеальных тестах.

// Отсюда главный вред, и он не в потерянном времени. Команда привыкает: красное - это «наверное, опять мигает». Перезапускают не глядя. И однажды так перезапустят настоящий дефект, который уедет в прод, то есть к живым пользователям. Набор, которому не верят, хуже отсутствия набора: он ещё и создаёт ложное чувство защищённости.

флаки-тест
на неизменном коде результат меняется от прогона к прогону
почему перемножается
прогон зелёный, только если прошли все тесты сразу

Три источника и лечение каждого

Первый - ожидание времени вместо события. Замер: тест ждёт фиксированные 15 миллисекунд там, где ответ приходит за 5-25, - падает в 51% прогонов. Поставил паузу 30 миллисекунд - падений ноль, но каждый тест теперь стоит вдвое дороже: на двухстах тестах 6 секунд вместо 3. А ожидание самого условия дало ноль падений при той же скорости, что у короткой паузы. Лечение: ждать событие, а не отрезок времени.

Второй - общие данные. Я запустил 60 тестов, работающих с одним списком, в несколько потоков. На одном потоке прошли все. На четырёх провалились 59 из 60: каждый тест ожидал увидеть результат только своих действий, а видел ещё и чужие. Лечение: свои данные на каждый тест, уникальные имена, очистка после себя. Параллельный запуск тут работает как проявитель - если тесты падают только вместе, они делят состояние.

// Третий - зависимость от времени и случайности. Я проверил наивную функцию «прибавить месяц к сегодняшней дате»: в 2026 году она падает ровно в 7 дней - 29, 30 и 31 января, 31 марта, мая, августа и октября. То есть тест зелёный 358 дней в году, а в семь дней краснеет, и разработчик честно отвечает «не воспроизводится». Лечение: фиксированная дата в тесте вместо сегодняшней и заданное зерно случайности - число, с которого генератор начинает, чтобы последовательность повторялась от прогона к прогону.

изоляция теста
свои данные, независимость от порядка и от соседей
детерминизм
одинаковый вход даёт одинаковый результат: фикс времени и зерно случайности

Перезапуск, карантин, наблюдение

Самое популярное «лечение» - перезапуск упавшего теста - на самом деле обезболивающее. Посчитаем: тест мигает в 20% прогонов, ставим три повтора. Вероятность, что хотя бы один из них зелёный, - 99,2%. Прогон становится зелёным почти всегда, и проблема исчезает с радаров. Ровно с той же вероятностью прячется и настоящий редкий дефект: он ведь тоже проявляется не каждый раз.

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

// И за стабильностью наблюдают числами: доля успешных прогонов по каждому тесту за месяц, список самых мигающих, время прогона. Тогда чинят по данным, а не по последнему впечатлению. Отдельно фиксируют окружение: версии браузера и библиотек, подменённые внешние сервисы - всё, что делает прогон повторяемым.

карантин
мигающий тест вынесен из блокирующего прогона и снабжён задачей на починку
цена перезапуска
три повтора прячут мигание в 99% случаев - вместе с редким настоящим багом

Как отвечать: «Что такое флаки-тест и что с ним делать?»

Флаки-тест - это тест, который на одном и том же коде то падает, то проходит. Опасен он не сам по себе, а масштабом: чтобы прогон был зелёным, должны пройти все тесты, поэтому вероятности перемножаются. Я считал: при нестабильности всего полпроцента на тест набор из двухсот тестов зелёный лишь в тридцати семи процентах прогонов, а из тысячи - меньше чем в одном. Дальше включается человеческий фактор: команда привыкает, что красное - это «опять мигает», перезапускает не глядя, и однажды так пропустит настоящий баг. Поэтому мигание я не игнорирую, а ищу причину, и причин по сути три. Ожидание времени вместо события - замерял, фиксированная пауза давала пятьдесят один процент падений, ожидание условия ноль при той же скорости. Общие данные - шестьдесят тестов на одном наборе данных в четыре потока провалили пятьдесят девять из шестидесяти, лечится изоляцией. И зависимость от даты и случайности - лечится фиксированной датой и зерном. Если починить прямо сейчас нельзя, увожу тест в карантин с задачей. Чего не делаю - не перезапускаю до зелёного: три повтора прячут мигание в девяноста девяти процентах случаев, а вместе с ним и редкий настоящий дефект.

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

На чём валят

  • Перезапускать до зелёного: три повтора прячут мигание в 99% случаев вместе с редким багом.
  • Лечить мигание увеличением паузы - вдвое медленнее, а на другой машине опять упадёт.
  • Считать 0,5% нестабильности мелочью: на 200 тестах зелёный прогон остаётся в 37% случаев.
  • Общие тестовые данные: те же 60 тестов в 4 потока провалили 59.
  • Сегодняшняя дата в тесте - 7 дней в году красных и вечное «не воспроизводится».

Проверьте себя

Пять вопросов из банка по этой подтеме. Всего их 12, остальные разбираются в тренажёре.

  1. #reliability1 / 5
    Каковы частые причины флаки-тестов?
    A)Основная причина флаки — слишком короткий таймаут, и лечится он его увеличением
    B)Гонки и асинхронность, зависимость от порядка и общих данных, время и рандом, обращения к внешним сервисам
    C)Флаки возникает от опечаток в коде теста, которые компилятор не смог обнаружить заранее
    D)Тесты флакают из-за нехватки оперативной памяти на машине непрерывной интеграции
    показать ответ и разбор
    +B)Гонки и асинхронность, зависимость от порядка и общих данных, время и рандом, обращения к внешним сервисам

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

  2. #reliability2 / 5
    Почему автотесты стараются делать независимыми друг от друга?
    A)Чтобы тесты выполнялись строго в одном и том же порядке при каждом прогоне набора
    B)Чтобы уменьшить общее число тестов за счёт объединения зависимых проверок в один
    C)Каждый стартует из известного состояния и не зависит от других
    D)Чтобы каждый тест мог напрямую менять данные, подготовленные предыдущим тестом
    показать ответ и разбор
    +C)Каждый стартует из известного состояния и не зависит от других

    // разбор: Независимый тест сам готовит нужное состояние (данные, сессию) и не опирается на то, что оставил предыдущий. Это даёт три важных свойства. Первое — любой порядок: тесты можно переставлять и запускать по одному, не таща за собой цепочку предшественников. Второе — параллельный прогон: независимые тесты не мешают друг другу и ускоряют набор. Третье — точная диагностика: падение указывает именно на свой тест, а не на «сломалось где-то раньше по цепочке». Зависимые же тесты рушатся каскадом, флакают от перестановки и скрывают, что реально сломано. Независимость обеспечивают через setup/teardown и изоляцию данных.

  3. #reliability3 / 5
    Что делают setup и teardown в автотесте?
    A)Setup запускает тест, а teardown формирует итоговый отчёт о его прохождении
    B)Setup компилирует код теста, а teardown выгружает его из памяти после прогона
    C)Setup и teardown замеряют время выполнения теста для отчёта о производительности
    D)Setup готовит данные и состояние до теста, teardown убирает следы после
    показать ответ и разбор
    +D)Setup готовит данные и состояние до теста, teardown убирает следы после

    // разбор: Setup (подготовка, fixture) выполняется до теста и приводит систему в известное исходное состояние: создаёт нужные данные, логинит пользователя, поднимает соединения. Teardown выполняется после теста и убирает за ним следы: удаляет созданные записи, закрывает соединения, откатывает изменения. Вместе они обеспечивают, что каждый тест стартует «с чистого листа» и не оставляет мусора для следующих. Это фундамент независимости и воспроизводимости: без setup тест зависит от случайного текущего состояния, без teardown — засоряет среду и роняет соседей. Многие фреймворки дают хуки before/after для этого.

  4. #reliability4 / 5
    Почему нельзя завязывать один тест на результат другого (на порядок)?
    A)Порядок-зависимый набор рушится при перестановке или параллели и прячет, какой тест на самом деле сломан
    B)Потому что зависимые тесты выполняются медленнее независимых на той же машине CI
    C)Потому что фреймворки автоматизации запрещают запускать тесты в заданном порядке
    D)Потому что тест, зависящий от другого, не попадает в итоговый отчёт о прогоне
    показать ответ и разбор
    +A)Порядок-зависимый набор рушится при перестановке или параллели и прячет, какой тест на самом деле сломан

    // разбор: Если тест B рассчитывает, что тест A уже создал запись и залогинил пользователя, набор становится хрупкой цепочкой. Переставили тесты, отключили один, запустили в параллель или по одному — и B падает не потому, что в нём баг, а потому что A не отработал первым. Такое падение вводит в заблуждение: красный B, а причина в A или в порядке. Кроме того, зависимость запрещает параллельный прогон (ускорение) и осложняет отладку — непонятно, что чинить. Правильно — каждый тест самодостаточен: сам создаёт нужное состояние в setup, не полагаясь на соседей. Тогда падение точно указывает на виновника.

  5. #reliability5 / 5
    Авто-ретрай упавшего флаки-теста — это решение проблемы или её маскировка?
    A)Ретрай устраняет флаки, поскольку при повторе тест уже не сталкивается с гонкой
    B)Ретрай прячет симптом, но не устраняет причину
    C)Ретрай ускоряет набор, потому что перезапуск теста выполняется быстрее первого прогона
    D)Ретрай нужен, чтобы отличить флаки от реального бага: если прошёл со второго раза — это баг
    показать ответ и разбор
    +B)Ретрай прячет симптом, но не устраняет причину

    // разбор: Автоматический перезапуск упавшего теста (retry until pass) делает сборку зелёной, скрывая факт нестабильности. Проблема в том, что это лечение симптома: причина недетерминизма (гонка, данные, время) остаётся, тест продолжает флакать, а команда теряет сигнал о реальной нестабильности. Хуже — ретрай может замаскировать и настоящий периодический баг продукта, который проявляется через тот же нестабильный тест. Разумнее: разобраться в причине флаки и устранить её (ожидания, изоляция, моки), а пока не починили — временно вынести тест в карантин (не блокирует сборку, но виден). Ретрай допустим как крайняя мера с обязательным трекингом, а не как способ «замести» флаки.

дальше

Теорию прочитали. Навык ставится повторением

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