Руководство · Cursor · Тесты
Как проверить изменения от ИИ: минимальный набор тестов
После diff Cursor Agent зафиксируйте критерий готовности - какой сценарий не должен сломаться. Локально: lint/typecheck, smoke или тесты затронутого модуля, для крупных правок - маркер regression. Полный suite - в CI на PR. Зелёный прогон агента - черновик; merge PASS остаётся у вас после review.

Как устроен тестовый контур после правок ИИ в Cursor
Agent в Cursor умеет менять десятки файлов и сам запускать terminal (overview). Это не отменяет вашу ответственность за merge: в best practices прямо сказано, что review обязателен, а зелёный прогон внутри сессии - не финальный gate. Автотесты здесь не про «покрыть всё на 90%», а про обратимость: вы знаете, какой сценарий сломался, до деплоя.
На наставничестве я начинаю не с pytest, а с критерия готовности. Пример из недавнего разбора: Telegram-бот принимает заявку с лендинга, пишет в CRM без дублей, отвечает пользователю за три секунды. Пока этот путь не проверен - merge рано, даже если агент уверенно отчитался о lint. Тестовый контур - мост между diff и продом.
Cloud Agent и песочницы вроде LangChain sandbox закрывают другой разрыв: у агента есть VM, где он может собрать проект и прогнать тесты до PR (cloud agent). Но без вашего минимального набора локально цикл не замыкается: среда агента не равна вашему staging, а hooks «пока тесты не зелёные» работают только если тесты вообще есть в репо.
Три слоя, которые я держу в голове после каждого Apply All:
- 01
Быстрый локальный прогон - lint, typecheck, targeted test на затронутый модуль.
- 02
Регрессия затронутого сценария - не весь репозиторий, а путь, который правили.
- 03
Полный suite на PR в CI -
pull_requesttrigger (GitHub Actions).
Если тестов в проекте нет совсем - честный минимум: один smoke-скрипт на критический путь плюс ручная проверка формы. Написание автотестов с нуля - отдельная задача; здесь - что гонять уже сегодня, когда Agent только что переписал handler.
Матрица «тип diff - минимальный прогон» экономит вечер:
| Тип diff | Минимум до merge | Регрессия |
|---|---|---|
| Косметика / copy / CSS | lint + ручной smoke страницы | полный suite не нужен |
| Одна функция / модуль | pytest path/to/test_*.py или npm test -- file | тесты модуля + 1 критический E2E/smoke |
| API-контракт / сигнатура | typecheck + тесты вызывающих мест | маркер regression / affected paths |
| Зависимости / конфиг / CI | lockfile diff + npm ci / build | полный CI на PR |
| Миграция БД / платёж / auth | интеграционный сценарий + откат | полный регресс + staging |
Перед первым промптом в новом репо полезно открыть первый проект в Cursor - там вечерний цикл Plan → Agent → verify. Здесь углубляем только тестовую часть verify.

Как покрыть unit-тестами первый контур
Unit тесты проверяют один кусок логики изолированно: функцию расчёта скидки, парсер телефона, валидацию email. Юнит тесты не ловят «кнопка на лендинге не кликается» - для этого smoke или E2E. После правок ИИ я смотрю, какие функции затронул diff, и гоняю тесты именно этого модуля, а не весь пакет.
Приоритет покрытия на разборах бизнес-репо:
- 01
Деньги и доступ: расчёт цены, лимиты, проверка роли, токен webhook.
- 02
Данные клиента: нормализация телефона, дедупликация заявки, маппинг полей в CRM.
- 03
Контракты между модулями: что API handler ожидает на входе и отдаёт наружу.
- 04
Пограничные значения: пустая строка, ноль, слишком длинный ввод - агенты любят «счастливый путь».
- 05
Ошибки с понятным кодом: 400 vs 500, чтобы прод не глотал сбой молча.
Типичная картина: агент переписал normalize_phone() и добавил тест только на +7999.... Старый кейс с 8 (999) падает в проде. Я прошу в промпте: «добавь unit тесты на все форматы из README и на пустой ввод». Agent иногда делает это хорошо - но прогон остаётся у вас.
Для JavaScript тот же принцип: npm test -- src/utils/phone.test.ts бьёт в один файл, не ждёт всего Jest suite. Для Python - pytest tests/test_phone.py -k normalize. Не гоняйте триста тестов после правки одной строки в CSS - это другая строка матрицы выше.
Когда unit тестов мало, я добавляю один «якорный» тест на бизнес-правило, которое уже ломалось. Не ради метрик покрытия - ради сигнала при следующем diff. Один тест на «заявка не уходит дважды при двойном клике» полезнее десяти на геттеры.
Связка с Cursor: в rules можно прописать «после изменения src/billing/ запускай npm test -- billing». Agent иногда слушается, иногда нет - terminal-команда в чате не заменяет ваш локальный прогон перед commit.

Как прогнать регрессию после каждого diff
Регрессионное тестирование отвечает на вопрос: старое поведение живо после новой правки? Регрессионные тесты - не отдельная религия, а набор сценариев, которые уже однажды спасли от бага. После diff от Agent я не запускаю «всё подряд», а выбираю слой по ширине изменений из таблицы в первом разделе.
Узкий diff в одном модуле: тесты модуля плюс один критический smoke. Пример - правка handler Telegram-бота: pytest tests/test_bot_handlers.py и ручная отправка тестовой заявки на staging-бота. Широкий diff в package.json или миграции БД: полный CI на PR, staging, план отката.
В pytest маркеры smoke и regression помогают разделить скорость и глубину (pytest mark):
# быстрый контур после мелкой правки
pytest -m smoke
# перед merge крупной фичи
pytest -m regressionМаркеры нужно один раз описать в pytest.ini или pyproject.toml - иначе -m smoke ничего не найдёт. Agent часто добавляет тесты без маркеров; тогда targeted path надёжнее абстрактного -m.
Регрессия для API-контракта: если агент поменял сигнатуру createLead(payload), гоняю тесты всех мест, которые импортируют эту функцию, плюс typecheck (tsc --noEmit или mypy). Сломать вызывающий код - частый побочный эффект «улучшения» от модели.
На разборе лендинга с формой я фиксирую регрессионный сценарий текстом: «отправка с валидным телефоном → 200 → запись в таблице → письмо в Telegram». Пока цепочка не зелёная - не merge. Это и есть регрессионное тестирование без фанатизма: один живой путь, который приносит деньги.
CI на pull_request - место для полного suite. Локально - targeted. Если гонять всё на ноутбуке после каждого Apply All, устанете и начнёте пропускать verify - я это вижу у соло-основателей на третьей неделе с Agent.

Как запустить автотесты на Python через pytest
pytest - мой дефолт для автотестов на python в бизнес-скриптах, ботах и небольших API. Соглашение простое: файлы test_*.py, проверки через assert, запуск одной командой (getting started). Не tutorial TDD с нуля - быстрый старт, чтобы после Cursor было что нажать.
Минимальный тест после правки модуля:
# tests/test_lead_normalize.py
from app.leads import normalize_phone
def test_normalize_strips_spaces():
assert normalize_phone("8 (999) 123-45-67") == "+79991234567"
def test_normalize_rejects_empty():
assert normalize_phone("") is NoneЗапуск только этого файла - не весь репозиторий:
pytest tests/test_lead_normalize.py -qДля smoke-набора после мелкого diff:
pytest -m smoke --maxfail=1 -qФлаги -q и --maxfail=1 экономят время: первый красный тест останавливает прогон, вы сразу видите причину в логе для промпта Agent.
pytest тесты агент часто пишет прилично, но любит захардкодить «счастливый» API-ключ в фикстуре. Перед commit проверяю diff на SECRET, TOKEN, реальные URL продакшена. Это пересекается с проверкой кода от ИИ, но повторю: тестовый файл тоже попадает в git.
Если проект на Node - та же логика, другая команда: npm test -- src/leads/phone.test.ts. Написание автотестов на python или JS следует одной матрице из первого раздела; меняется только runner.
Структура папки, которую я рекомендую на разборах:
| Путь | Назначение |
|---|---|
tests/unit/ | чистая логика, быстрый прогон |
tests/integration/ | БД, внешние API, staging credentials |
pytest.ini | маркеры smoke, regression |
Agent без явного промпта кладёт всё в tests/test_foo.py - нормально для старта. Маркеры и split на unit/integration можно сделать отдельной задачей, когда контур уже спасает от регресса.
Минимальный чеклист перед merge и деплоем
Чеклист - это не бюрократия, а пять минут, которые отделяют «агент сказал готово» от «форма в проде реально шлёт заявку». Я прохожу его сам после каждого крупного Apply All и даю ученикам как скрипт в terminal history.
Пять шагов после Apply All:
# 1. lint / format
npm run lint # или ruff check . / eslint по проекту
# 2. targeted test на затронутый модуль
pytest path/to/test_module.py -q
# JS: npm test -- path/to/file.test.ts
# 3. regression marker, если diff шире одного файла
pytest -m regression --maxfail=3 -q
# 4. push ветки - CI на pull_request
git push -u origin HEAD
# 5. smoke критического пути (ручной или скрипт)
# пример: curl staging /health и тестовая заявка в формуШаг 4 не заменяет шаги 1-3. CI ловит то, что вы запушили; если локально не гоняли targeted test, в PR уедет красный build и вы потеряете время на цикл «push - ждать - чинить».
Для предпринимателя без dev-фона критерий готовности удобнее держать в JSON рядом с задачей - не в pytest, а как контракт «что значит готово»:
{
"feature": "lead_form_to_telegram",
"ready_when": [
"форма на /contact принимает +7 и 8",
"дубликат за 60 сек не создаёт вторую запись в CRM",
"сообщение приходит в Telegram-чат менеджеров",
"пользователь видит экран «спасибо», не 500"
],
"smoke_command": "npm run test:smoke -- contact-form",
"owner_review": true
}Такой файл можно положить в docs/acceptance/ или в корень как acceptance-lead-form.json. Agent читает его через @acceptance-lead-form.json в промпте - и вы сверяете прогон с пунктами ready_when, а не с абстрактным «всё работает».
Таблица «когда какой шаг обязателен»:
| Ситуация | Шаги 1-2 | Шаг 3 regression | Шаг 4 CI | Ручной smoke |
|---|---|---|---|---|
| Правка текста на лендинге | lint | нет | по желанию | да, одна страница |
| Новый handler в боте | да | да | да | тестовое сообщение боту |
| Обновление зависимостей | build | полный CI | да | критический путь |
| Платёж / auth | интеграционные | полный | да + staging | сценарий отката |
Зелёный прогон Agent в чате не ставлю галочку в чеклисте - только вывод команд, которые я сам скопировал в terminal и увидел exit code 0. Как проверить код ии агента на практике - воспроизвести команды у себя, а не скриншот из сессии.
Перед merge сверяюсь с Git и Cursor: ветка не main, diff просмотрен, commit после зелёного verify. Тесты - следующий слой той же дисциплины.
Что ломается: типичные ошибки автотестов и как их чинить
Здесь не общие советы «пишите больше тестов», а симптомы с фиксом, которые я ловлю на разборах после Cursor.
Flaky: тест то зелёный, то красный
Симптом: pytest падает на таймере, sleep или сравнении datetime.now(). Агент любит time.sleep(1) вместо мока часов. Фикс: freezegun или dependency injection времени; для async - явный await с таймаутом в тесте, не в прод-коде. Локально гоняю три раза подряд: pytest tests/test_x.py --count=3 (если установлен pytest-repeat) или простой цикл в shell. Если хоть раз красный - не merge.
Ложнозелёный: тест проходит, прод падает
Симптом: assert слишком слабый - assert result is not None вместо проверки значения. Или тест бьёт в мок, а прод ходит в реальный API. Фикс: assert на конкретное поведение из ready_when; один интеграционный тест без мока на staging credentials. Ещё вариант - тест импортирует старую функцию из кэша после rename: pytest --cache-clear и проверка, что путь импорта в тесте совпадает с diff.
Импорты и окружение: ModuleNotFoundError после Agent
Симптом: агент добавил tests/test_foo.py, но package не в PYTHONPATH, или виртуальное окружение в terminal Cursor не то. Фикс: запуск из корня репо с активированным venv; в pyproject.toml или setup.cfg проверить pythonpath = .. Для monorepo - pytest apps/bot/tests с -c apps/bot/pytest.ini. В промпте: «запусти pytest из корня и приложи полный traceback» - и чините по логу, не по словам «у меня прошло».
Дополнительные частые сбои:
| Симптом | Вероятная причина | Фикс |
|---|---|---|
| Все тесты skipped | неверный маркер -m | pytest --collect-only |
| CI красный, локально зелёный | другая версия Node/Python | сверить .nvmrc / python-version в Actions |
| Тест падает только в CI | нет env var | secrets в GitHub, не в тесте |
| Agent «починил» тест удалением assert | ослабление проверки | diff теста обязателен в review |
Ошибка, которую видел чаще всего: ученик merge после того, как Agent закомментировал падающий assert «временно». Временно - до инцидента в проде. Я возвращаю assert и чиню код, не тест.
Разобрать тестовый контур на вашем проекте
Если после прочтения остались вопросы «а у меня тестов нет» или «агент уже прогнал всё сам» - это нормальные возражения. На разборах я не продаю курс TDD: смотрим ваш репозиторий, фиксируем один критерий готовности, добавляем smoke или targeted pytest там, где боль уже была. Без магического процента покрытия и без обещания zero bugs.
Три типичных входа:
- 01
Тестов нет - один smoke на заявку/оплату/логин плюс lint; дальше наращиваем по матрице diff.
- 02
Тесты есть, но долго - маркеры
smoke/regression, targeted path после Agent. - 03
Агент в Cloud - настраиваем минимальный прогон в VM, но merge PASS остаётся у вас после review ветки.
По теме в блоге: как проверять код от ИИ (diff, секреты, lint), Git и Cursor (ветка, откат), первый проект в Cursor (вечерний цикл с нуля).
Частые вопросы
Нужны ли тесты, если код правит ИИ в Cursor?
Да. Agent пишет черновик и может запустить команды в terminal, но merge и ответственность за прод остаются у вас. Минимум после diff: lint, targeted test на затронутый модуль или smoke критического сценария. Полный suite - на PR в CI.
Сколько unit-тестов достаточно после правки агента?
Не привязывайтесь к проценту покрытия. Достаточно тестов на затронутую логику плюс один регрессионный сценарий, который уже ломался. После правки одной функции - файл тестов этого модуля; после смены API - тесты всех вызывающих мест.
Чем unit-тесты отличаются от регрессионных?
Unit проверяют один кусок логики изолированно - функцию, парсер, расчёт. Регрессионные отвечают на вопрос «старое поведение живо?» - цепочка заявка → CRM → Telegram или оплата → чек. После diff от Agent сначала unit затронутого модуля, при широких изменениях - маркер regression или полный CI.
Как проверить код перед выкладкой в прод?
Локально: lint, targeted pytest или npm test на изменённые файлы, ручной smoke критического пути по критерию готовности. Затем push ветки и зелёный CI на pull_request. Staging для платежей, auth и миграций БД. Зелёный отчёт агента в чате не заменяет ваш прогон команд в terminal.
pytest падает сразу после Apply All в Cursor - что делать?
Скопируйте полный traceback в промпт Agent, не merge. Частые причины: ModuleNotFoundError (неверный PYTHONPATH), сломанный импорт после rename, ослабленный assert, который агент «починил» комментарием. Запускайте из корня репо с активированным venv: pytest path/to/test_file.py -q.
Нужно ли гонять CI после каждого коммита агента?
Локально - targeted test после каждого зелёного шага, полный CI - при push ветки на pull_request. Не обязательно триггерить pipeline на каждый промежуточный commit в feature-ветке, если вы ещё в середине задачи. Перед merge в main - зелёный CI обязателен.
Как проверить код ИИ агента, если проект на JavaScript, а не Python?
Та же матрица diff → минимальный прогон. Вместо pytest: npm test -- path/to/file.test.ts, npm run lint, typecheck через tsc. Маркеры smoke и regression можно настроить в Jest или Vitest. Смысл не в языке, а в targeted прогоне затронутого модуля и CI на PR.
Связанные страницы

Обсудить вашу задачу
Напишите в Telegram цель, что уже сделано и где стопор.
Отвечаю сам — без бота и «оставьте заявку».




