Agent Dev 101

Модуль 09 · Урок 9.1

Урок 9.1. Почему тесты становятся важнее при AI

На этой странице
  1. Зачем это нужно
  2. Основная идея
  3. Ключевые термины
  4. Почему скорость меняет требования
  5. Self-report агента не доказательство
  6. Evidence-based completion
  7. Baseline перед изменениями
  8. Когда baseline особенно важен
  9. Manual check vs automated evidence
  10. "Агент проверил глазами" не равно test
  11. Роль tests в agent workflow
  12. Что проверять при agent-generated change
  13. Verification ladder
  14. Verification budget
  15. Tests как защита от AI failure modes
  16. Acceptance criteria и tests
  17. Baseline checklist
  18. Completion checklist
  19. Пример: без verification
  20. Пример: с evidence
  21. Что делать с failing checks
  22. Testing не заменяет review
  23. Testing не заменяет specification
  24. Как встроить это в prompts
  25. Практика: verification checklist для task
  26. Практика: manual vs automated evidence
  27. Типичные ошибки
  28. Критерии готовности
  29. Краткое резюме
  30. Вопросы для самопроверки
  31. Что дальше

Зачем это нужно

AI-агент может написать код очень быстро. Это главный плюс и одновременно главный риск.

Человек обычно пишет медленнее. Он дольше держит задачу в голове, чаще видит локальные детали, иногда интуитивно замечает несостыковки. AI может за минуты создать большой diff: новые файлы, tests, migrations, routes, UI states, docs. Но скорость генерации не равна скорости понимания и не равна качеству результата.

Поэтому в agentic development меняется баланс:

text
Generation speed ↑
        ↓
Required verification ↑

Чем быстрее агент производит изменения, тем сильнее должен быть слой проверки. Иначе команда начинает принимать код по уверенности текста, а не по evidence.

Главная цель урока - понять, почему tests, typecheck, lint, build и acceptance checks становятся центральным механизмом доверия к AI-generated changes.

Основная идея

В традиционной разработке тесты нужны, потому что люди ошибаются.

В AI-assisted development тесты нужны еще сильнее, потому что:

  • код генерируется быстрее;
  • diff может быть больше;
  • агент может звучать уверенно даже при ошибке;
  • модель может неправильно понять spec;
  • модель может пропустить edge case;
  • модель может не заметить нарушение существующего контракта;
  • модель может "проверить логически", но не выполнить код;
  • один человек может запускать несколько agent tasks подряд.

Тесты становятся не просто quality practice, а control system.

Формула:

text
Trust the evidence, not the narration.

Агент может объяснить, что он сделал. Но принимать результат стоит по проверяемым сигналам:

  • tests passed;
  • typecheck passed;
  • lint passed;
  • build passed;
  • acceptance criteria mapped;
  • diff reviewed;
  • failures reported honestly.

Ключевые термины

Термин Значение
Verification Проверка, что изменение работает и не нарушает важные ограничения.
Evidence Проверяемое подтверждение результата: команда, exit code, test result, diff, AC status.
Self-report Утверждение агента о том, что все работает. Само по себе не является доказательством.
Baseline Состояние проверок до изменения или перед началом task.
Regression Поломка ранее работавшего поведения.
Acceptance Check Проверка, что acceptance criterion выполнен.
Automated Test Проверка, выполняемая машинно и повторяемо.
Manual Check Проверка человеком или агентом без автоматизированного утверждения.
Typecheck Проверка типов без запуска runtime behavior.
Lint Проверка стиля, потенциальных ошибок и соглашений.
Build Проверка, что проект собирается.
Test Signal Информация, которую дает test: pass, fail, error, skipped, flaky, not run.

Почему скорость меняет требования

Когда скорость генерации растет, risk profile меняется.

flowchart TD A[AI generates code faster] --> B[More changes per unit time] B --> C[Larger review surface] C --> D[More hidden assumptions] D --> E[Higher regression risk] E --> F[Need stronger automated verification] F --> G[Trust based on evidence]

Если раньше разработчик мог вручную проверить маленький patch, то с агентом возникает другой режим:

text
Много маленьких diff быстро
или
один большой diff слишком быстро

В обоих случаях manual checking начинает отставать. Поэтому автоматическая verification становится ограничителем скорости:

text
AI generation speed can increase only as far as verification can keep up.

Self-report агента не доказательство

Агент может написать:

text
Готово, я проверил, все работает.

Но это может означать разные вещи:

  • агент реально запустил tests;
  • агент посмотрел на код и решил, что должно работать;
  • агент хотел запустить tests, но не смог;
  • агент перепутал command output;
  • агент не заметил failing test;
  • агент проверил не тот scope;
  • агент говорит уверенно, потому что так выглядит хороший финальный ответ.

Поэтому final answer должен содержать evidence.

Плохо:

text
Готово. Тесты должны проходить.

Лучше:

text
Verification:
- `npm test -- tests/api/projects.test.ts`: passed, exit code 0
- `npm run typecheck`: passed, exit code 0

Acceptance criteria:
- valid create: satisfied by API test
- invalid name: satisfied by API test

Если проверки не запускались:

text
Verification:
- `npm test -- tests/api/projects.test.ts`: not run
  Reason: dependencies are not installed.

Residual risk:
- Runtime behavior has not been verified locally.

Честный "not run" лучше, чем красивое "should work".

Evidence-based completion

Task завершена не тогда, когда агент закончил писать код. Task завершена, когда есть evidence.

Минимальная evidence для coding task:

Evidence Пример
Changed files src/api/projects.ts, tests/api/projects.test.ts
Targeted test npm test -- tests/api/projects.test.ts
Exit code/result passed, exit code 0
Type/lint/build npm run typecheck, npm run lint, npm run build
AC status AC1 satisfied, AC2 satisfied
Diff review no unrelated changes
Limitations full suite not run, DB unavailable

Evidence должна быть конкретной. Не нужно длинное эссе. Нужно, чтобы человек мог понять:

text
Что изменилось?
Чем проверено?
Что осталось непроверенным?

Baseline перед изменениями

Baseline - это знание о состоянии проекта до изменения.

Зачем он нужен:

  • отличить новую поломку от уже существующей;
  • понять, какие проверки доступны;
  • увидеть flaky или failing tests заранее;
  • выбрать targeted verification;
  • не обвинять agent diff в старых проблемах;
  • не принимать new failure как "так и было" без доказательств.

Baseline может быть легким:

text
Перед task:
- `npm test -- tests/api/projects.test.ts`: passed
- `npm run typecheck`: passed

Или ограниченным:

text
Baseline not run:
- Task is small docs-only change.
- Existing CI status is unknown.

Не всегда нужно запускать весь suite до каждого изменения. Но для рискованных задач полезно знать хотя бы ближайший baseline.

Когда baseline особенно важен

Baseline стоит сделать, если:

  • task затрагивает shared module;
  • test suite уже подозрительно нестабилен;
  • нужно исправить bug;
  • меняется architecture boundary;
  • меняется database schema;
  • меняется public API;
  • несколько agents работают параллельно;
  • рабочее дерево уже dirty;
  • expected failure нужно воспроизвести до fix.

Для bug fix baseline часто выглядит как reproduction:

text
Before fix:
- `pytest tests/auth/test_reset_token.py::test_reuse_rejected`: failed

After fix:
- same test: passed

Это сильная evidence: bug действительно был воспроизведен и исправлен.

Manual check vs automated evidence

Manual checking полезен, но плохо масштабируется.

Критерий Manual check Automated evidence
Повторяемость Низкая Высокая
Скорость на regression Низкая Высокая
Документируемость Часто слабая Команда и result
Покрытие edge cases Зависит от человека Можно фиксировать cases
Усталость Высокий риск Ниже
Подходит для UI feel Да Частично
Подходит для API contract Плохо Хорошо
Подходит для bug fix Только как дополнение Лучше через regression test

Manual check не запрещен. Он нужен для:

  • visual quality;
  • UX feel;
  • exploratory testing;
  • accessibility review;
  • сложных edge cases;
  • поведения, которое трудно автоматизировать быстро.

Но manual check должен быть явно назван:

text
Manual check:
- Opened settings page.
- Created a project through UI.
- Verified success toast and navigation.

Automated checks:
- not available for this UI flow.
Residual risk:
- no regression coverage for browser behavior.

"Агент проверил глазами" не равно test

Агент может сделать static reasoning:

text
Я просмотрел код, логика корректна.

Это полезно, но это не automated verification.

Разделяйте:

Тип проверки Что доказывает
Static inspection Код выглядит согласованным с pattern.
Typecheck Типы согласованы.
Lint Нет части статических нарушений.
Unit test Локальная logic работает на cases.
Integration test Компоненты вместе дают expected behavior.
E2E test User/system flow работает целиком.
Contract test Boundary соответствует contract.
Manual check Человек или агент проверил сценарий руками.

Static inspection - это слой. Но не единственный.

Роль tests в agent workflow

Tests нужны агенту не только в конце. Они управляют всем loop.

flowchart LR A[Spec] --> B[Acceptance Criteria] B --> C[Test Plan] C --> D[Write or Update Test] D --> E[Implement] E --> F[Run Test] F --> G{Pass?} G -- No --> H[Use failure as feedback] H --> E G -- Yes --> I[Review Diff] I --> J[Report Evidence]

Тест дает агенту обратную связь. Без теста агенту приходится полагаться на собственную уверенность.

AI особенно хорошо работает, когда у него есть fast feedback:

  • failing test;
  • compiler error;
  • type error;
  • lint output;
  • snapshot diff;
  • contract mismatch;
  • migration failure.

Feedback превращает модель из генератора текста в участника engineering loop.

Что проверять при agent-generated change

Минимальный набор зависит от задачи.

Для backend endpoint:

  • API/integration test;
  • service/unit test, если есть pattern;
  • typecheck;
  • contract check, если есть OpenAPI;
  • lint, если быстрый.

Для frontend form:

  • component test;
  • validation cases;
  • accessibility smoke check;
  • visual/screenshot check, если UI важен;
  • typecheck/build.

Для database migration:

  • migration apply check;
  • schema diff;
  • model tests;
  • backward compatibility check;
  • rollback/dry-run, если проект требует.

Для docs-only change:

  • markdown lint, если есть;
  • link check, если есть;
  • review diff.

Для bug fix:

  • reproduction;
  • failing regression test before fix;
  • targeted regression after fix;
  • broader tests if shared behavior changed.

Verification ladder

Если невозможно выполнить идеальный test, используйте ladder.

text
Best:
Automated test proving AC.

Good:
Targeted test + typecheck/lint.

Acceptable with caveat:
Static inspection + manual check + explicit residual risk.

Bad:
"The agent thinks it works."

Смысл ladder не в том, чтобы оправдывать отсутствие тестов. Смысл в том, чтобы честно назвать уровень confidence.

Verification budget

Проверки стоят времени. Нельзя всегда запускать все.

Нужно выбирать:

  • closest test first;
  • cheap static checks early;
  • broader suite when shared code changed;
  • expensive E2E only when risk оправдан;
  • manual check when automation unavailable.

Пример:

text
Change: validation schema for one endpoint.

Run:
1. endpoint API test
2. validation unit test if exists
3. typecheck

Skip:
- full E2E suite unless endpoint affects core flow

Хороший агент объясняет, почему выбран такой набор verification.

Tests как защита от AI failure modes

AI failure mode Как помогает testing
Hallucinated API Typecheck/build ловят nonexistent imports/functions.
Misread requirement AC-to-test traceability показывает mismatch.
Overbroad refactor Diff review + regression tests ловят unintended changes.
Missing edge case Explicit test cases фиксируют boundary behavior.
Wrong integration assumption Integration test проверяет реальные boundaries.
Silent failure Exit codes и logs дают evidence.
Confident false claim Test result важнее self-report.
Stale context Running tests проверяет текущий код, а не память модели.

Тесты не делают модель безошибочной. Они делают ошибки видимыми.

Acceptance criteria и tests

Каждый важный acceptance criterion должен иметь:

text
automated test
или
explicit manual check
или
осознанный residual risk

Пример:

Acceptance Criterion Verification
Valid project name creates project API integration test
Empty name rejected API validation test
Owner is current user Service/API test assertion
Response returns project id API integration test
UI button disabled while loading Component test or manual UI check

Это мост к уроку 9.3 Specification -> Tests.

Baseline checklist

Перед изменением:

text
[ ] Прочитан spec
[ ] AC выписаны
[ ] Найдены existing tests
[ ] Понятно, какую проверку запускать
[ ] При bug fix воспроизведен failure
[ ] Известны текущие failing tests, если они есть
[ ] Понятны commands для targeted verification

Если baseline не сделан, это не всегда блокер. Но агент должен понимать, что confidence ниже.

Completion checklist

Перед финальным ответом:

text
[ ] Tests added/updated where practical
[ ] Targeted tests run
[ ] Typecheck/lint/build run when relevant
[ ] Failed checks reported
[ ] Not-run checks explained
[ ] Diff reviewed
[ ] AC status reported
[ ] Residual risk named

Эта checklist должна стать привычкой. Без нее agent-generated changes выглядят быстрее, чем они реально безопасны.

Пример: без verification

Task:

text
Добавь endpoint POST /api/projects.

Плохой финал:

text
Готово. Я добавил endpoint, validation и service. Все должно работать.

Что не так:

  • нет changed files;
  • нет tests;
  • нет command output;
  • нет AC mapping;
  • нет diff review;
  • "должно работать" не evidence.

Пример: с evidence

Хороший финал:

text
Summary:
- Added POST /api/projects endpoint with request validation and service integration.

Changed files:
- src/api/projects.ts
- src/services/projects.ts
- tests/api/projects.test.ts

Verification:
- npm test -- tests/api/projects.test.ts: passed, exit code 0
- npm run typecheck: passed, exit code 0

Acceptance criteria:
- Valid name creates project: satisfied by API test.
- Empty name returns validation error: satisfied by API test.
- Project belongs to current user: satisfied by service assertion.
- Response returns 201 with project id: satisfied by API test.

Residual risk:
- Full E2E suite was not run.

Такой ответ можно проверить, обсудить и принять в review.

Что делать с failing checks

Falling check - это сигнал, не стыд.

Агент должен:

  1. Сохранить точный command и failure summary.
  2. Понять, failure связан с текущим diff или baseline.
  3. Исправить, если failure в scope.
  4. Не исправлять unrelated failure без разрешения.
  5. Не ослаблять test ради зеленого результата.
  6. Сообщить residual risk, если failure остается.

Пример:

text
Verification:
- npm test -- tests/api/projects.test.ts: failed, exit code 1
  Failure: expected 201, got 401.

Analysis:
- Failure is in scope: endpoint uses auth middleware but test lacks authenticated user.

Next step:
- Update test setup to use existing authenticated helper.

Или:

text
Verification:
- npm test: failed in unrelated `billing.test.ts`.

Analysis:
- Billing test was failing before this task according to baseline.
- Current endpoint test passed.

Residual risk:
- Full suite remains red; not caused by this diff based on baseline.

Testing не заменяет review

Passing tests не означают, что diff идеален.

Tests могут не ловить:

  • unnecessary complexity;
  • bad naming;
  • architecture drift;
  • missing observability;
  • security design flaw;
  • wrong abstraction;
  • poor UX;
  • incomplete docs;
  • performance risk.

Поэтому loop остается:

text
tests + diff review + AC check

А не только:

text
tests pass

Testing не заменяет specification

Тесты отвечают:

text
Проверяется ли конкретное поведение?

Spec отвечает:

text
Какое поведение должно быть?

Если spec плохая, агент может написать tests на неправильное поведение.

Поэтому порядок важен:

text
Spec -> Acceptance Criteria -> Tests -> Implementation -> Verification

Не наоборот.

Как встроить это в prompts

Плохой prompt:

text
Сделай фичу.

Лучше:

text
Сделай фичу через evidence-based loop.

Перед изменениями:
- прочитай spec;
- выпиши acceptance criteria;
- найди existing tests;
- предложи verification plan.

Во время работы:
- добавь или обнови targeted tests where practical;
- реализуй минимальный diff.

Перед финалом:
- запусти targeted tests;
- запусти typecheck/lint/build if relevant;
- проверь diff;
- сопоставь AC с tests/results;
- сообщи commands, exit codes, failures и residual risk.

Такой prompt задает стандарт доверия.

Практика: verification checklist для task

Task:

text
Bug: reset password token can be reused after successful reset.

Заполните:

text
Acceptance criteria:
1.
2.
3.

Baseline/reproduction:
- command:
- expected before fix:

Test to add/update:
- file:
- scenario:

Verification after fix:
- targeted test:
- broader test:
- typecheck/lint/build:

Manual checks, if any:

Residual risk:

Возможное заполнение:

text
Acceptance criteria:
1. Consumed reset token cannot be reused.
2. Expired token is rejected.
3. Successful reset invalidates token.

Baseline/reproduction:
- command: pytest tests/auth/test_password_reset.py::test_reset_token_reuse
- expected before fix: fails because reused token is accepted

Test to add/update:
- file: tests/auth/test_password_reset.py
- scenario: use token once, then attempt second reset with same token

Verification after fix:
- targeted test: pytest tests/auth/test_password_reset.py
- broader test: pytest tests/auth
- typecheck/lint/build: project-specific commands if available

Residual risk:
- email delivery flow not covered by this regression test

Практика: manual vs automated evidence

Сравните два финальных отчета.

Report A

text
Готово. Я вручную просмотрел код, проблема исправлена.

Report B

text
Changed files:
- app/auth/reset.py
- tests/auth/test_password_reset.py

Verification:
- pytest tests/auth/test_password_reset.py::test_reset_token_reuse: passed, exit code 0
- pytest tests/auth: passed, exit code 0

Acceptance criteria:
- token cannot be reused: satisfied by regression test

Residual risk:
- full application suite not run

Вопросы:

  1. Какой отчет можно использовать в review?
  2. Какой отчет помогает future regression protection?
  3. Какой отчет честнее говорит о residual risk?

Ответ очевиден, но в реальных проектах команды часто принимают Report A, потому что агент звучит уверенно. Вот почему нужна дисциплина.

Типичные ошибки

Ошибка Симптом Исправление
Верить self-report "Agent said it works" Требовать commands/results.
Не делать baseline Непонятно, новая ли поломка Запускать targeted baseline where useful.
Нет test для bug fix Bug может вернуться Добавить regression test.
Только manual check Сложно повторить Автоматизировать key AC.
Игнорировать failed tests "Потом починим" Report and classify failure.
Ослаблять tests Suite зеленеет, behavior ломается Tests должны следовать spec.
Запускать только full suite Медленно и шумно Start targeted, broaden by risk.
Не сообщать not-run checks Ложное confidence Explicit limitation.
Не связывать tests с AC Проверки есть, но feature неполная AC-to-test mapping.
Tests без diff review Passing tests, но плохой scope Review diff separately.

Критерии готовности

После урока студент должен уметь:

  • объяснить, почему AI увеличивает потребность в verification;
  • отличить self-report от evidence;
  • назвать минимальные элементы evidence-based completion;
  • объяснить baseline и когда он нужен;
  • сравнить manual check и automated evidence;
  • выбрать проверки для backend/frontend/migration/docs/bug fix tasks;
  • составить verification checklist;
  • честно описать not-run checks и residual risk.

Краткое резюме

AI ускоряет генерацию кода. Поэтому tests и другие проверки становятся важнее, а не менее важными.

Главная формула:

text
Generation speed ↑
        ↓
Required verification ↑

И главный принцип:

text
Trust evidence, not narration.

Evidence-based completion требует changed files, commands, results, acceptance criteria status, diff review и residual risk. Агент может быть полезным генератором изменений только тогда, когда система проверки успевает за скоростью генерации.

Вопросы для самопроверки

  1. Почему self-report агента не считается доказательством?
  2. В каких задачах baseline особенно важен?
  3. Чем manual check хуже automated evidence, и когда он все равно нужен?
  4. Что должен содержать final verification report?
  5. Почему passing tests не заменяют diff review и acceptance criteria check?

Что дальше

В следующем уроке мы разберем test pyramid: unit, integration, E2E, contract, snapshot, visual, migration, security и performance checks. Нам нужно научиться выбирать не просто "писать тесты", а какой уровень теста подходит к конкретному acceptance criterion и риску изменения.

Обновлено 03.10.2026