| name | tdd |
| description | Помогать реализовывать функции и исправлять баги по TDD-циклу: один падающий поведенческий тест, минимальная правка, затем безопасный рефакторинг. Использовать, когда пользователь просит работать test-first, через TDD, red-green-refactor или хочет сначала зафиксировать ожидаемое поведение тестом. Навык не привязан к конкретному языку программирования. |
TDD
Работай по TDD-циклу: сначала один падающий тест на наблюдаемое поведение, затем минимальная правка, затем безопасный рефакторинг только при зеленых тестах.
Навык не зависит от языка программирования. Используй язык, тестовый фреймворк, стиль и соглашения конкретного проекта. Если в проекте уже есть тесты, ориентируйся на существующие паттерны тестирования, стиль именования, фикстуры, фабрики, fake-объекты и способ запуска тестов.
Главная цель
Помочь пользователю реализовать функцию или исправить баг так, чтобы:
- поведение было зафиксировано тестами до реализации;
- тесты проверяли публичное поведение, а не внутренние детали;
- код развивался маленькими вертикальными срезами;
- реализация оставалась минимальной до появления следующего теста;
- рефакторинг происходил только после зеленого состояния.
Базовый цикл
RED
Напиши один тест на одно важное поведение.
Убедись, что тест падает по ожидаемой причине.
GREEN
Напиши минимальный код, чтобы тест прошел.
Убедись, что новый тест и существующие тесты проходят.
REFACTOR
Улучши дизайн без изменения поведения.
После каждого изменения снова запускай тесты.
Не пиши весь набор тестов заранее. Не реализуй несколько будущих сценариев до того, как для них появились тесты.
Перед началом
- Определи публичное поведение, которое должно появиться или измениться.
- Определи публичный интерфейс, через который это поведение должно проверяться.
- Найди самый маленький полезный вертикальный срез.
- Если доступна кодовая база, изучи существующие тесты и текущий стиль реализации.
- Если вопрос можно надежно закрыть через код, документацию или тесты, сначала изучи их, а не спрашивай пользователя.
- Если ключевое продуктовое или архитектурное решение нельзя вывести из контекста, задай один конкретный вопрос.
Как выбирать первый тест
Первый тест должен быть маленьким, но проходить через реальный публичный путь системы.
Хороший первый тест:
- проверяет один end-to-end сценарий;
- описывает результат, важный для пользователя, вызывающего кода или системы;
- использует публичный интерфейс;
- не привязан к приватным методам и внутренним вызовам;
- может быть запущен независимо;
- падает до реализации.
Плохой первый тест:
- проверяет приватный метод;
- утверждает порядок внутренних вызовов;
- мокает собственные внутренние классы;
- фиксирует будущую архитектуру до того, как она доказана тестами;
- требует реализации большого объема кода сразу.
Вертикальные срезы
Развивай поведение через tracer bullets — тонкие вертикальные срезы.
Каждый срез должен давать проверяемый результат, а не просто изменение одного технического слоя.
Плохо:
1. Добавить схему данных
2. Добавить слой доступа к данным
3. Добавить API
4. Добавить интерфейс
5. Добавить тесты
Хорошо:
1. Пользователь может создать минимальный черновик сущности и увидеть его в списке
2. Пользователь может открыть черновик и увидеть сохраненные данные
3. Пользователь получает ошибку при попытке сохранить невалидные данные
Правила тестирования
Следуй этим правилам по умолчанию:
- тестируй наблюдаемое поведение;
- используй публичные интерфейсы;
- проверяй результат, состояние или внешний эффект, а не внутренний путь выполнения;
- избегай тестов, которые ломаются от безопасного рефакторинга;
- не тестируй приватные методы напрямую;
- не мокай внутренние модули собственного кода;
- мокай или подменяй только внешние границы системы;
- предпочитай fake-объекты и in-memory реализации, когда они дают более устойчивый тест, чем mock;
- не добавляй функциональность без теста, который ее требует.
Когда задавать вопросы
Задавай вопрос только если без ответа нельзя выбрать корректный публичный контракт или ожидаемое поведение.
Хорошие вопросы:
- Какой результат должен увидеть пользователь в этом сценарии?
- Что должно произойти при невалидном вводе?
- Это поведение должно быть синхронным или асинхронным с точки зрения вызывающего кода?
- Какая внешняя система является настоящей границей, которую нужно подменять в тесте?
Не спрашивай пользователя о деталях, которые можно выяснить из проекта:
- как называются существующие тестовые файлы;
- какой тестовый фреймворк используется;
- как запускаются тесты;
- какие фикстуры уже есть;
- как устроены похожие сценарии.
Как работать с кодовой базой
Если проект доступен:
- Найди существующие тесты рядом с похожей функциональностью.
- Определи стиль тестов: unit, integration, end-to-end, fixtures, factories, fake-объекты.
- Определи способ запуска тестов.
- Найди публичный интерфейс, через который лучше проверять поведение.
- Избегай создания нового тестового стиля без необходимости.
- После каждого цикла запускай минимально достаточный набор тестов, затем более широкий набор перед финалом.
Как отвечать пользователю
Когда работаешь через TDD, показывай ход небольшими шагами:
- Какое поведение сейчас фиксируется.
- Какой тест будет написан.
- Почему тест должен падать.
- Какая минимальная реализация нужна.
- Что можно отрефакторить после зеленого состояния.
- Какой следующий срез логично взять.
Не перепрыгивай сразу к полной реализации.
Подробные руководства
Используй вспомогательные файлы в этой папке, когда нужно углубить конкретный аспект навыка:
guides/behavior-tests.md — как писать тесты поведения;
guides/vertical-slices.md — как идти тонкими end-to-end срезами;
guides/deep-modules.md — как выделять глубокие модули;
guides/interface-design.md — как проектировать тестируемые интерфейсы;
guides/mocking.md — когда использовать mock, fake и stub;
guides/refactoring.md — как рефакторить после GREEN;
guides/checklist.md — чеклист TDD-цикла.