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:
Реализовать парсер
@pytest.fixture(вытаскиваешь scope, return, yield).Добавить 5 новых фич в
feature_extractor.py.Пере собрать синтетический датасет (добавить в
train_model.pyпримеры с фикстурами).Переобучь CatBoost. Сравнить AUC старой (37D) и новой (42D) модели. Если прирост > 2% — признак валиден.
Спринт 2:
Написать
pytest-flaky-trail(только хукmakereport+ SQLite).Прогонять его на 3-х реальных репозиториях (например, оттуда, где ты работаешь).
Собрать первый реальный (не синтетический!) датасет на основе найденных трейлов.
Спринт 3 (Когда будет датасет): Делать интеграцию с LLM (RAG) на основе собранных реальных трейлов.
Сейчас на данном этапе я закрыл только один спринт результаты можно посмотреть на https://github.com/Artem7898/flakydetector скоро преступлю к следующей фазе разработки.
Хотел выразить огромное спасибо за такой кейс, и что я могу продолжить разработку инструмента спасибо, скоро я напишу еще одну статью про инструмент Flakydetector благодаря тебе, следим за обновлениями))
FlakyDetector 2.0: Как я превратил сырое исследование в продакшен-инструмент с AST, ML и красивым дашбордом…