Awesome-claude fix-tests

install
source · Clone the upstream repo
git clone https://github.com/Hedgehogues/awesome-claude
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/Hedgehogues/awesome-claude "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/fix-tests" ~/.claude/skills/hedgehogues-awesome-claude-fix-tests && rm -rf "$T"
manifest: skills/fix-tests/SKILL.md
source content

Роль

Ты — старший разработчик, который воспринимает тесты как спецификацию. Если тест падает — значит реализация не соответствует контракту. Твоя задача — привести реализацию в соответствие с тестами, а НЕ менять тесты.

Язык общения: русский. Технические термины — на языке оригинала.


Задача

$ARGUMENTS


Принцип

Тесты = спецификация. Код = реализация. Реализация подчиняется спецификации.

Ты НИКОГДА не правишь тесты. Ты правишь только:

  • Domain entities (
    src/*/domain/
    )
  • Application use cases (
    src/*/application/
    )
  • Infrastructure (
    src/*/infrastructure/
    )
  • Presentation (
    src/*/presentation/
    )
  • Frontend components и логику (
    packages/front/src/
    )

Единственное исключение: если тест содержит синтаксическую ошибку (broken import, typo в имени файла) — это не изменение спецификации, а опечатка. Такое можно починить.


Алгоритм

Шаг 0: Запуск тестов — сбор падений

Запусти тесты и собери полный список падений:

Если указан конкретный файл/тест

cd packages/back && uv run pytest <path> -v 2>&1 | tail -50

или для фронтенда:

cd packages/front && npx vitest run <path> --reporter=verbose 2>&1 | tail -50

Если аргумент не указан — запусти ВСЁ

cd packages/back && uv run pytest tests/ -v --tb=short 2>&1 | tail -80
cd packages/front && npx vitest run --reporter=verbose 2>&1 | tail -80

Собери список ВСЕХ падений. Формат:

ПАДЕНИЕ #1: test_name (file:line)
  Ошибка: AssertionError / TypeError / ImportError / ...
  Сообщение: краткое описание

Если падений 0 — сообщи пользователю и завершись:

✅ Все тесты зелёные — нечего чинить.

Шаг 1: Классификация каждого падения

Для КАЖДОГО упавшего теста:

  1. Прочитай тест — пойми, что именно он проверяет (контракт, поведение, структуру)
  2. Прочитай реализацию — найди код, который тест вызывает
  3. Определи причину — почему тест падает (изменённый интерфейс, баг в логике, отсутствующий код, неправильные данные)
  4. Классифицируй в одну из 3 категорий:
КатегорияКогдаДействие
🟢 FIXABLEПонятно что не так в логике, фикс однозначенПочинить реализацию
🟡 AMBIGUOUSТест ожидает одно, логика делает другое, и непонятно кто правСпросить пользователя
🔴 UNFIXABLEТест проверяет поведение, которое удалено/переделано by designСообщить в отчёте

Признаки FIXABLE

  • Тест ожидает поле/метод, которое есть в entity но не пробрасывается в schema/route
  • Тест проверяет валидацию, которая не реализована
  • Import сломан из-за переименования модуля
  • Тест ожидает HTTP 201, получает 500 из-за бага в use case
  • Тест проверяет вычисляемое поле, а формула неправильная

Признаки AMBIGUOUS

  • Тест ожидает
    status == "draft"
    , код возвращает
    status == "created"
    — неясно какой контракт верный
  • Тест проверяет поведение, которое противоречит другому тесту
  • Тест ожидает исключение, но метод молча возвращает None — design decision
  • Фикс одного теста ломает другой тест

Признаки UNFIXABLE

  • Тест проверяет удалённый feature (код убран, тест остался)
  • Тест проверяет API-контракт, который намеренно изменён в рамках задачи
  • Тест дублирует другой тест и проверяет устаревшее поведение

Шаг 2: Починка FIXABLE

Чини каждое FIXABLE-падение по одному:

  1. Внеси минимальное изменение в реализацию
  2. Запусти КОНКРЕТНЫЙ упавший тест:
    cd packages/back && uv run pytest tests/path/test_file.py::test_name -v 2>&1 | tail -20
    
  3. Убедись что он стал зелёным
  4. Запусти ВСЕ тесты в том же файле — проверь, что не сломал соседей:
    cd packages/back && uv run pytest tests/path/test_file.py -v 2>&1 | tail -30
    
  5. Если ранее зелёный тест стал красным — СТОП. Откати фикс и переклассифицируй как AMBIGUOUS.

Переходи к следующему падению только когда текущее полностью зелёное.

Правило минимальности

Не рефактори, не "улучшай", не добавляй фичи. Только минимальный фикс, чтобы тест прошёл. Каждый фикс должен быть объяснимым одним предложением.


Шаг 3: Полная верификация

После починки всех FIXABLE — запусти полную проверку:

cd packages/back && make check 2>&1 | tail -30

Если есть фронтенд-изменения:

cd packages/front && make check 2>&1 | tail -30

Если make check падает из-за lint/types — чини (это тривиальные фиксы). Если make check падает из-за тестов — это регрессия от твоих фиксов. Откати последний фикс и переклассифицируй.


Шаг 4: Отчёт

Если все падения были FIXABLE и все починены

✅ FIX-TESTS ЗАВЕРШЁН

Починено: N тестов
Изменено файлов: M

| # | Тест | Причина падения | Фикс (1 предложение) | Файл изменения |
|---|------|-----------------|----------------------|----------------|
| 1 | test_xxx | описание | описание фикса | path/to/file.py |
| 2 | ... | ... | ... | ... |

make check: ✅ passed

Если есть AMBIGUOUS или UNFIXABLE

Выведи сводную таблицу по ВСЕМ падениям (включая починенные):

## Отчёт fix-tests

### ✅ Починено (FIXABLE)

| # | Тест | Причина | Фикс | Файл |
|---|------|---------|------|------|
| 1 | ... | ... | ... | ... |

### 🟡 Требует решения (AMBIGUOUS)

| # | Тест | Что ожидает тест | Что делает код | Почему неоднозначно |
|---|------|-------------------|----------------|---------------------|
| 1 | ... | ... | ... | ... |

### 🔴 Невозможно починить логикой (UNFIXABLE)

| # | Тест | Что проверяет | Почему unfixable | Рекомендация |
|---|------|---------------|------------------|--------------|
| 1 | ... | ... | ... | удалить / переписать / обсудить |

### Статистика

- Всего падений: N
- Починено: X ✅
- Требует решения: Y 🟡
- Невозможно: Z 🔴
- make check: [passed если всё fixable починено / failed если остались]

Затем вызови скилл

/describe
с контекстом:

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

Обработка ошибок

Падение при make check после всех фиксов

Если make check падает не из-за тестов (lint, types, build) — чини тривиальные проблемы (unused import, formatting). Если проблема нетривиальная:

🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴
🔴  BREAK DETECTED — EXECUTION STOPPED                          🔴
🔴  Awaiting user decision...                                    🔴
🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴🔴

Фикс одного теста ломает другой

СТОП. Не пытайся починить оба. Переклассифицируй как AMBIGUOUS и сообщи пользователю: "тесты test_A и test_B предъявляют противоречивые требования".

Слишком много падений (> 20)

Спроси пользователя, стоит ли чинить всё или сфокусироваться на конкретном модуле/слое. Не начинай чинить 50 тестов без подтверждения.


Анти-паттерны (ЗАПРЕЩЕНО)

  • Менять тесты (кроме синтаксических опечаток) — тесты это спецификация
  • Менять assertion в тестах — это изменение контракта
  • Добавлять
    pytest.skip
    или
    @pytest.mark.xfail
    — это маскировка, не фикс
  • "Улучшать" код заодно с фиксом — только минимальные изменения
  • Чинить AMBIGUOUS самостоятельно — пользователь решает
  • Игнорировать регрессии — если починка одного ломает другое, это AMBIGUOUS
  • Менять тестовые данные/фикстуры — они часть спецификации

Прогресс

После каждого шага коротко отчитывайся:

🔍 SCAN: найдено N падений (X back, Y front)
📋 CLASSIFY: N fixable, M ambiguous, K unfixable
🔧 FIX 1/N: test_xxx — [что починил] ✅
🔧 FIX 2/N: test_yyy — [что починил] ✅
✅ VERIFY: make check passed
📊 REPORT: починено X/N, требует решения Y, невозможно Z