Pull to refresh
2
Дарья@Ariless

QA Automation Engineer

0,4
Rating
3
Subscribers
Send message

Хороший вопрос, я для себя сейчас выделяю несколько сигналов, которые важнее, чем просто pass/fail.

Количество реально запущенных тестов
Не “зелёный CI”, а соответствие ожидаемому набору. Любое отклонение (меньше или больше) - это уже сигнал о системе, а не о тестах.

Тренд времени выполнения
Важно не абсолютное время, а изменение. Если пайплайн постепенно замедляется без изменений в тестах, то это почти всегда деградация инфраструктуры или данных.

Flaky rate
Сколько тестов за последние запуски дают нестабильный результат. Флаки редко про “плохой тест”, а чаще про скрытое состояние или неявные зависимости между тестами.

Contract drift
Если есть API-схемы или контракты, то важно отслеживать расхождение между ожиданиями тестов и фактическим поведением системы, а не только отдельные ассёрты.

И главное - всё это обычно не сложно добавить технически. Сложнее заранее сформировать привычку это измерять, пока система ещё “выглядит зелёной”.

Когда просишь агента написать тест, самое важное - не “что проверить”, а контекст вокруг теста: fixtures, shared state, порядок выполнения. Без этого получаешь тест, который зелёный в изоляции и падает в CI - не потому что агент написал плохо, а потому что он не знал, как устроено окружение.

С debugging через логи то же самое. В Playwright перешла от пошагового дебага к описанию symptom chain: что тест ожидал, что получил, в каком порядке шли другие тесты. Агент находит паттерн быстрее, чем ручной дебаг.

Статья упоминает важную цифру — AI-код содержит в 1.7 раза больше проблем на pull request, чем человеческий.

С точки зрения QA это создаёт интересную ловушку: если команда использует AI и для написания кода, и для написания тестов - оба артефакта генерируются в одном контексте, с одними и теми же слепыми пятнами. Тест проверяет то, что агент предполагал написать, а не то, что система должна делать.

На практике это проявляется тихо: тесты зелёные, CI доволен, но coverage покрывает предположения агента, а не реальное поведение. Классический silent failure. Лечится не количеством тестов, а разделением контекста: тест-сценарии пишутся до кода и независимо от него.

В секции про качество есть слой, который в статье не дораскрыт.

“Тесты покрывают только happy path” - это первый уровень проблемы. Но когда агент пишет и код, и тесты в одном контексте, появляется второй уровень: оба артефакта несут одни и те же предположения. Тест не просто пропускает edge cases, он подтверждает то, что агент предполагал реализовать. CI становится зелёным, и это выглядит как сигнал “всё правильно”. Хотя на самом деле это сигнал “агент с собой согласен”.

Был похожий кейс из практики. Fixture создавала тестовый слот с фиксированными timestamp’ами. В изоляции тест всегда был зелёным. В CI при определённом порядке запуска появлялся SLOT_OVERLAP.

Агент может прочитать спеку, контракты и весь код теста, и не найти там ничего подозрительного. Потому что проблема живёт не в документах, а в том, как тесты взаимодействуют друг с другом во времени: порядок запуска, shared state, побочные эффекты между прогонами. Это слой, который не индексируется.

Тезис про "валидацию внутри агентного цикла" интересный, но там есть скрытая проблема: агент валидирует собственный вывод с теми же слепыми зонами, с которыми он его генерировал. Если валидация переезжает внутрь агентного цикла, возникает вопрос: кто валидирует саму валидацию?

Агент-ревьюер может проверить тесты и код, но не весь контур исполнения - как CI запускает проверки, как устроена изоляция, какие состояния разделяются между прогонами.

Был практический кейс: после миграции JS → TS CI выглядел зелёным, тесты проходили, но Playwright подхватывал оба расширения и запускал один и тот же набор тестов дважды. С точки зрения "внутреннего агента" всё корректно - тесты зелёные.

Статья хорошо описывает переход к "continuous compute", но не поднимает слой observability этого контура. А без него агентный цикл может завершаться успешно и именно это будет проблемой.

Time pressure is real, and I'm not arguing every flaky test deserves immediate investigation.

The distinction I'd make: "we know this is environment noise, accepting the risk" vs "unclear root cause, we'll look later." The first is a conscious tradeoff. The second is where the signal quietly disappears.

The BrowserStack case fit the second pattern exactly - it looked like infrastructure noise, which is precisely why it was close to being filed and forgotten. The config problem only surfaced because I kept digging instead of labeling it flaky-infrastructure and moving on.

В QA-автоматизации та же история: в некоторых проектах код теста уже считается конфиденциальным, потому что раскрывает структуру системы. Отдельная история когда тест работает с реальными данными из staging.

Из того что вижу в своей работе: облачные инструменты хорошо заходят там где нет чувствительных данных — генерация шаблонов, разбор логов, объяснение поведения. Как только начинается "смотри, вот наш API контракт", начинаются вопросы к безопасности.

Пока on-prem не догонит по качеству — это будет работать только для части команд.

Статья хорошо описывает разработческую перспективу. Со стороны QA automation есть нюанс про ограниченный контекст, который в статье упомянут вскользь.

Агент может предложить изменения в тестах, которые локально зелёные, но конфликтуют с CI-конфигурацией, потому что файл конфига не попал в его контекст. У меня был конкретный кейс: при миграции JS→TS агент не увидел, что Playwright подхватывает оба расширения. CI продолжал работать без ошибок и просто гонял каждый тест дважды.

Это не баг агента — это именно та «ошибка предположений об инфраструктуре», про которую в статье написано. Просто в тестовом окружении она проявляется специфически.

Согласна, CI не виноват, он проверяет ровно то, что ему сказали проверять. Это и есть суть проблемы.

Про npx playwright test --list | wc -l — это рабочий вариант, и да, он бы поймал. Но есть нюанс: чтобы добавить такую проверку, нужно сначала знать, что считать тесты вообще стоит. До инцидента это не казалось очевидным, CI зелёный, тесты проходят, зачем считать?

Именно об этом статья: не о том, что CI плохой инструмент, а о том, что мы неосознанно приравниваем "тесты прошли" к "система работает корректно". И это предположение не проверяем пока что-то не идёт не так.

Упрощаешь ли ты? Технически нет, добавить счётчик несложно. Но engineering-проблема не в сложности реализации, а в том, что никто не думает добавлять проверку на то, что считает очевидным.

Интересная архитектура, особенно иерархия приоритетов при RCA. Вопрос про edge case: что происходит, когда root cause не вписывается ни в одну категорию иерархии?

Иерархия "тест → фреймворк → приложение" покрывает большинство случаев, но есть отдельный класс проблем - shared state между тестами. Код теста чистый, фреймворк работает корректно, приложение тоже. Проблема в порядке выполнения и взаимодействии между тестами, а не внутри одного теста.

Это особенно актуально для Android UI: если несколько тестов работают с одним и тем же UI-состоянием или данными без полной изоляции - RCA агент может искать причину не в том слое.

Если агент неверно классифицирует причину, fix будет уверенным, но неправильным. Как обрабатываете случаи, когда ни одна категория не подходит?

Разграничение точное - сетевой запрос подтверждает что операция завершилась, но не то что пользователь получил визуальную обратную связь. Это разные требования.

Буфер с накоплением событий - логичное решение для нескольких toast подряд. В Playwright делаю похоже: page.route() с счётчиком вызовов для stateful сценариев, где важен порядок событий, а не только факт появления.

Риск-оценка особенно неочевидна когда баг технически “работает правильно”.

Был случай: endpoint возвращал 422 INVALID_STATUS неавторизованному пользователю вместо 403 FORBIDDEN. Формально — корректный статус, логика не сломана. Но 422 раскрывал что запись существует и находится в конкретном статусе. Неавторизованный пользователь получал информацию о чужих данных через error code.

По критерию “видимость проблемы после выпуска” — незаметно. По критерию “влияние на личную информацию” — блокирующий.

Именно такие баги сложнее всего аргументировать на go/no-go: симптом выглядит косметически, а риск — в том что система говорит больше чем должна.

Паттерн с перехватом toast-уведомлений через "чёрный ящик" — один из самых неочевидных в UI-тестировании.

В Playwright та же проблема решается через page.waitForSelector или перехват через page.route, но race condition никуда не девается: toast появляется и исчезает быстрее, чем тест успевает его поймать. Особенно в CI, где браузер работает медленнее.

Мне помог другой подход — перехватывать не DOM-элемент, а сетевой запрос, который toast отображает.

Если toast показывает результат операции, можно ждать завершения запроса, а не появления элемента. Это убирает зависимость от скорости рендеринга.

Но ваш MutationObserver с буфером звучит надёжнее для случаев, когда toast не связан с конкретным запросом. Как решаете ситуацию, когда несколько toast-уведомлений появляются подряд?

К пункту про CI/CD хочу добавить нюанс, который не очевиден на старте.

Интеграция с CI - это правильно. Но есть ловушка: зелёный CI быстро становится синонимом "всё работает". А это не одно и то же.

Был кейс: после миграции с JavaScript на TypeScript CI продолжал быть зелёным, тесты проходили. Но Playwright начал подхватывать оба расширения (.spec.js и .spec.ts) — каждый тест запускался дважды. CI выполнял двойную работу без единого сигнала об ошибке. Нашли случайно, когда количество тестов внезапно упало вдвое при удалении JS-файлов.

CI - это не индикатор здоровья системы. Это индикатор того, что тесты прошли. Разница важна, особенно при миграциях и изменениях конфигурации.

Привет! Именно так и вышло в итоге - transactional fixture. В Playwright это function-scoped fixture: создаёт данные для конкретного теста, убивает их в teardown. Если предыдущий тест по какой-то причине не дочистил, то следующий всё равно начинает с чистого листа.

Интересный момент: решение оказалось архитектурным, не тестовым. Код самого теста не трогали, а только перевели fixture из shared scope в function scope. После этого SLOT_OVERLAP исчез полностью.

И вот здесь как раз проявляется "flakiness as a signal": тест падал не потому, что был плохо написан, а потому что подсвечивал реальный дефект в дизайне окружения. Если просто пометить его flaky и заглушить, то теряется единственный индикатор проблемы.

Про анализ зависимостей между тестами - очень жду. Особенно если инструмент сможет отвечать не только "есть order dependency", а конкретно: "тест B падает, потому что тест A не очистил состояние X". Рандомный порядок выполнения хорошо вскрывает связки, но почти не помогает локализовать источник загрязнения.

Кстати, твой пример с AST vs shared state отлично показывает границу между "code smell detection" и настоящим behavioural analysis. Это уже ближе к tracing/runtime observability, чем к классическому статическому анализу.

Результаты впечатляют, особенно 20% ускорение через адаптивные перезапуски. Но есть вопрос про triage.

Перезапуск решает симптом - тест перестаёт блокировать релиз. Но некоторые flaky тесты это не технический долг, а сигнал о реальной проблеме в системе.

У меня был кейс: тест падал с SLOT_OVERLAP только при определённом порядке запуска в CI. Перезапуск его "починил" бы - в следующем прогоне порядок другой, тест зелёный. Но проблема никуда не делась: fixtures использовали конфликтующие timestamp'ы, и при росте нагрузки это стало бы стабильным падением.

Как в вашем процессе отличаете "безопасный flaky" (таймаут, медленная среда) от "flaky как сигнал" (shared state, порядок выполнения, скрытая зависимость)? Или перезапуск применяется ко всем нестабильным тестам одинаково?

Вывод исследования совпадает с тем, что я наблюдала на практике.

Был кейс: тест падал с SLOT_OVERLAP, но код теста абсолютно чистый - никаких таймаутов, никаких внешних запросов, никаких очевидных антипаттернов. LLM, глядя только на код теста, не нашёл бы ничего подозрительного.

Проблема была во fixture: она создавала слот с фиксированными timestamp'ами, которые конфликтовали со слотом предыдущего теста. Если предыдущий тест не успел удалить свой слот, то новый fixture падал. В изоляции тест всегда зелёный, в CI при определённом порядке - падение.

Причина полностью вне кода теста, в shared state между тестами и порядке их выполнения. Код теста - это только видимая часть; flakiness живёт в окружении, конфигурации и взаимодействиях между тестами.

Поэтому любой подход, анализирующий только код теста, структурно ограничен.

Agreed with the core idea "tests exist not to pass, but to fail." But there's a nuance around flaky tests.

The article suggests disabling an unstable test and investigating later. The problem is that sometimes the instability itself is the finding.

One case: a test was failing during BrowserStack integration with an error that looked like a connectivity issue. Classic candidate for "disable and investigate later." But the real cause was different: safari is not a valid browser name in the Playwright SDK - you need webkit. A misleading error was hiding a fundamental configuration problem.

If we had disabled the test as "flaky due to BrowserStack", we would have only found this when the entire Safari run started failing in production.

A flaky test with an unclear cause is not technical debt. It's a signal. Disabling it means losing the only indicator of the problem.

Интересный подход, особенно комбинация AST + ML. Вопрос: как инструмент обрабатывает случаи, когда flakiness не в самом коде теста, а в shared state между тестами?

У меня был кейс: fixture создавала слот с фиксированными timestamp'ами. Код теста абсолютно чистый, никаких антипаттернов. Но если предыдущий тест не успел удалить свой слот - новый fixture падал с SLOT_OVERLAP. В изоляции тест всегда зелёный, в CI при определённом порядке падал.

37 признаков из AST это не обнаружат - там нет ничего подозрительного. Планируете добавлять анализ взаимодействий между тестами?

Information

Rating
2,616-th
Registered
Activity

Specialization

Инженер по автоматизации тестирования, Инженер по ручному тестированию
Старший
Git
Docker
JavaScript
TypeScript