раздел 05 · шаг 6/7
Шаг 6. Тесты
Покрытие бэка через pytest, фронта - через vitest + Testing Library. AI-вызов мокаем, чтобы не сжигать токены в CI. На выходе - coverage-отчёт.
Что делаем
- Расширяем pytest для бэка: CRUD кейсы, edge cases, мок Anthropic
- Поднимаем vitest на фронте
- Пишем юнит и компонент-тесты для React
- Подключаем coverage
Backend: тесты
Промпт для Claude
Расширь pytest-тесты в backend/tests/:
CRUD задач (tests/test_tasks_crud.py):
- POST с валидным title - 201, возвращается с id и created_at
- POST с пустым title - 422 (validation error)
- POST с title > 200 символов - 422
- GET /api/tasks - возвращает массив, сортировка created_at desc
- GET после нескольких POST - корректный порядок
- PATCH существующей задачи - меняет поля
- PATCH несуществующего id - 404
- PATCH с пустым body - возвращает задачу без изменений
- DELETE существующей - 204
- DELETE несуществующей - 404
- DELETE дважды - первая 204, вторая 404
AI-категоризация (tests/test_categorizer.py):
- Мок anthropic.AsyncAnthropic через monkeypatch
- categorize возвращает валидную категорию из мока - результат проходит
- Мок возвращает неизвестное слово - результат "other"
- Мок бросает APIError - результат "other", не падает
- Мок бросает TimeoutError - результат "other"
- В POST /api/tasks: проверяем что категория из мока попадает в БД
Используй:
- pytest-asyncio с asyncio_mode = "auto" в pyproject.toml или pytest.ini
- httpx.AsyncClient для интеграционных тестов
- pytest-mock для удобного monkeypatch (поставь pytest-mock в requirements)
- pytest-cov для coverage (тоже в requirements)
Скрипты в README:
- pytest -v - все тесты
- pytest --cov=app --cov-report=html - coverage в htmlcov/
Цель coverage: > 80% по app/
Запуск
source venv/bin/activate
cd backend
pip install -r requirements.txt
pytest -v
pytest --cov=app --cov-report=term --cov-report=html
Открыть отчёт: open htmlcov/index.html (на macOS).
Frontend: тесты
Промпт для Claude
Подключи vitest + Testing Library в frontend/:
Установи devDependencies:
- vitest
- @testing-library/react
- @testing-library/jest-dom
- @testing-library/user-event
- jsdom
- @vitest/coverage-v8
Конфиг vitest.config.ts:
- environment: jsdom
- setupFiles: ./src/test/setup.ts
- coverage с провайдером v8, report: text + html
В src/test/setup.ts:
- import "@testing-library/jest-dom/vitest"
Скрипты в package.json:
- "test": "vitest"
- "test:run": "vitest run"
- "test:coverage": "vitest run --coverage"
Тесты:
1. src/components/TaskInput.test.tsx
- render: input есть в DOM
- ввод текста + Enter вызывает onCreate с этим текстом
- после успешного создания input очищается
- в isPending input disabled
2. src/components/TaskItem.test.tsx
- render: title виден, чекбокс отражает task.done
- клик по чекбоксу вызывает onToggle с task.id
- клик по кнопке удалить вызывает onDelete с task.id
- бейдж категории показывает task.category
3. src/components/TaskList.test.tsx
- loading: показывает skeleton (3 элемента)
- error: показывает текст ошибки и кнопку Повторить
- empty: показывает приглашение
- filled: рендерит все задачи
Используй QueryClientProvider в обёртке (renderWithQuery утилита).
Мокай fetch через msw или vi.spyOn(global, 'fetch').
Запуск
cd frontend
pnpm install
pnpm test:run
pnpm test:coverage
Coverage-отчёт: frontend/coverage/index.html.
Что должно покрываться
Минимум для зелёного билда:
| Слой | Coverage цель |
| --- | --- |
| backend/app/routers/ | 90%+ |
| backend/app/services/ | 80%+ |
| backend/app/models/ | модели тестируются через роуты |
| frontend/src/components/ | 75%+ |
| frontend/src/lib/ | 90%+ |
Edge cases, про которые часто забывают
Если Claude в первой генерации их не покрыл - попросите явно:
- Пустой
title- не должен пройти валидацию - Очень длинный
title- валидация на длину categoryприсланная клиентом игнорируется (вычисляется AI)- Двойной DELETE одного и того же id
- PATCH с
done: null- что делает приложение? - Параллельные POST - проверьте что id не коллидят (SQLite одного соединения этого не покажет, но проверка не помешает)
Что НЕ нужно тестировать
- Сам факт того, что Anthropic API работает - это не наша зона ответственности
- Реальные сетевые вызовы в CI - только моки
- UI-снапшоты в TaskList - они хрупкие, лучше проверять конкретные элементы
Точка сохранения
cd ..
git add .
git commit -m "step 6: pytest for backend, vitest for frontend, coverage > 80%"
Полезные ссылки
- pytest - официальная документация
- Vitest - быстрый тест-раннер для Vite
- Testing Library React - паттерны для React-тестов
- MSW - моки сетевых запросов на уровне service worker