Pull to refresh

Comments 4

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

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

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

Привет! Ого, вот это кейс — прямо хрестоматийный пример той самой «дьявольской» сложности, с которой мы все сталкиваемся.

Во-первых, огромное спасибо за этот пример — в нём вскрывается настоящее ахиллесово пятно многих статических анализаторов.

Почему мой AST-анализ бессилен в твоём случае

Модель выдаст уверенные 99% с пометкой Чисто, потому что формально код безупречен нет sleep, нет мутаций глобальных переменных, нет сетевых вызовов. Пока не встанет в очередь за другим тестом. Исследования это подтверждают: около 59% нестабильных тестов в Python появляются именно из-за такого порядка выполнения.

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

· Динамический анализ через логи (как в FlakyXbert). Он сравнивает состояния в момент падения и прохода и может сказать: В момент прогона в слоте было занято, сейчас нет. · Анализ зависимостей данных (как в Peeler). Ищет цепочки: тест А что-то изменил → тест Б это прочитал. · Детерминированные стратегии выполнения. Простой, но мощный метод — инструменты вроде JS-TOD для JS специально прогоняют тесты в случайном порядке (10, 20, 50 раз). Если хоть раз упадёт — значит, есть скрытая связка.

Как это повлияет на мои планы по FlakyDetector

Я сейчас очень плотно изучаю два направления:

· Анализ связок тестов. Хочется не просто сказать У вас проблема в порядке тестов, а указать пальцем: Тест B падает, потому что тест A не почистил за собой конкретный слот. · LLM-классификация из коробки. Современные модели показывают очень достойные результаты в предсказании нестабильности по одному лишь коду, не требуя ручного выделения 37 признаков.

Поскольку я ещё только пилю следующий релиз, вот тебе мои «костыли»:

· pytest-randomly или pytest-xdist --random-order — прогони свои тесты в разнобой, и он тебе со 100% вероятностью упадёт. · Идеальным решением для твоей боли будет transactional fixture. Суть проста: тест запускается → фикстура создаёт слот → тест завершается → фикстура гарантированно всё откатывает. В этом случае все следы пребывания теста в БО уничтожаются, и соседям нечем пачкаться.

А твой кейс по ссылкам на ptvsd, mergify и замоканный datetime я с удовольствием изучу — как раз для полировки следующей версии.

Ещё раз спасибо за такой развёрнутый фидбек! Если будут ещё идеи или примеры — подкидывай. Пиши в комментариях, интересно обсудить.

Привет! Именно так и вышло в итоге - 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, чем к классическому статическому анализу.

Привет я не долго думая, решил кастомизировать свой проект на основе твоего кейса. Я разбил разработку на три спринта.

Спринт 1:

  1. Реализовать парсер @pytest.fixture (вытаскиваешь scope, return, yield).

  2. Добавить 5 новых фич в feature_extractor.py.

  3. Пере собрать синтетический датасет (добавить в train_model.py примеры с фикстурами).

  4. Переобучь CatBoost. Сравнить AUC старой (37D) и новой (42D) модели. Если прирост > 2% — признак валиден.

Спринт 2:

  1. Написать pytest-flaky-trail (только хук makereport + SQLite).

  2. Прогонять его на 3-х реальных репозиториях (например, оттуда, где ты работаешь).

  3. Собрать первый реальный (не синтетический!) датасет на основе найденных трейлов.

Спринт 3 (Когда будет датасет): Делать интеграцию с LLM (RAG) на основе собранных реальных трейлов.

Сейчас на данном этапе я закрыл только один спринт результаты можно посмотреть на https://github.com/Artem7898/flakydetector скоро преступлю к следующей фазе разработки.

Хотел выразить огромное спасибо за такой кейс, и что я могу продолжить разработку инструмента спасибо, скоро я напишу еще одну статью про инструмент Flakydetector благодаря тебе, следим за обновлениями))

Sign up to leave a comment.

Articles