Amiga
Оглавление курса · урок 6 из 17

Модуль 1 · Рабочий цикл · урок 6 из 17

Тесты как спецификация: TDD с агентом

С агентом TDD перестаёт быть вопросом дисциплины и становится вопросом контроля. Тесты, написанные до кода, — это спецификация, которую агент не может истолковать по-своему: он её либо прошёл, либо нет. А вы внимательно читаете не сотни строк реализации, а несколько десятков строк тестов.

Почему TDD и агенты хорошо сочетаются

Агенту нужен способ понять, что задача решена. Руководство OpenAI по лучшим практикам повторяет это несколько раз: Codex может сам писать тесты, запускать проверки и подтверждать результат, но только если знает, как выглядит «хорошо». Тест — самая точная форма такого знания, потому что он исполняется.

Саймон Уиллисон в гайде Agentic Engineering Patterns выделяет red/green TDD в отдельный приём работы с агентами. Сначала тест, который падает (red), потом реализация, после которой он проходит (green). Красный тест подтверждает, что тест вообще что-то проверяет. Зелёный — что код делает заявленное.

Для вас TDD с агентом переносит точку контроля. Вместо того чтобы вычитывать всю реализацию, вы вычитываете тесты: их меньше, и в них видно намерение.

Цикл по шагам

Пример: в плагине интернет-магазина на OctoberCMS нужна акция «третий товар бесплатно, если все три из одной категории; бесплатным становится самый дешёвый».

1. Тесты из критериев. Только тесты, без кода:

text
Правило акции — ниже. Напиши тесты PHPUnit для DiscountCalculator
в tests/Unit/DiscountCalculatorTest.php. Покрой основной сценарий
и граничные случаи: два товара, четыре товара, разные категории,
одинаковые цены, пустая корзина. Реализацию не пиши и пока ничего
не запускай — сначала покажи тесты.

Граничные условия — сильная сторона агента. В гайде OpenAI о внутреннем использовании Codex отмечено, что он хорошо находит пустые входы, предельные длины и необычные, но допустимые состояния. Ваша задача — убедиться, что эти случаи отражают бизнес-правило, а не догадку агента.

2. Вы утверждаете тесты. Это главный шаг. Читайте тесты как спецификацию:

php · tests/Unit/DiscountCalculatorTest.php
public function test_cheapest_of_three_same_category_is_free(): void
{
    $cart = $this->makeCart([
        ['price' => 1000, 'category' => 'shoes'],
        ['price' => 700,  'category' => 'shoes'],
        ['price' => 1500, 'category' => 'shoes'],
    ]);

    $this->assertSame(700, (new DiscountCalculator())->discountFor($cart));
}

К каждому тесту — вопрос: это требование бизнеса или выдумка агента? Что при четырёх товарах — бесплатен один или два? Если в критериях этого нет, вопрос к аналитику, а не к агенту. Неясность, найденная на этапе тестов, обходится дешевле, чем найденная тестировщиком или клиентом.

3. Красный. Агент запускает тесты и показывает, что они падают — потому что нет реализации, а не из-за ошибки в самом тесте:

bash
vendor/bin/phpunit --filter DiscountCalculatorTest

4. Зелёный. Реализация с жёстким ограничением:

text
Тесты утверждены. Реализуй DiscountCalculator так, чтобы они прошли.
Файлы в tests/ не меняй. Если считаешь, что тест неверен, остановись
и объясни, не исправляя его.

5. Рефакторинг. Когда всё зелёное, можно попросить упростить реализацию — тесты страхуют.

Как агент обходит тесты

Даже с запретом агенты иногда находят обходные пути. Что проверять в диффе:

  • Изменения в тестах. git diff --stat main -- tests/ должен показывать только утверждённое.
  • Подгонка под тест. Реализация с условиями на конкретные значения из тестов — классика. Помогает после реализации добавить случай, которого агент не видел.
  • Моки всего. Тест, в котором замокано всё, кроме одного return, проверяет моки. Для калькулятора скидок моки вообще не нужны — это чистая логика.
  • Тест на реализацию. Проверка «метод applyRule вызван дважды» ломается при любом рефакторинге и ничего не говорит о поведении. Просите проверять результат, а не внутренние вызовы.
  • Пропуски. markTestSkipped, перенос неудобного теста в медленную группу, фильтр, который запускает не всё.

Подробный чек-лист проверки тестов, написанных агентом, — в курсе для тестировщиков: «Как проверять тесты, написанные агентом».

Закрепите правила в AGENTS.md

markdown · AGENTS.md
## TDD
- Для новой бизнес-логики: сначала тесты, покажи их до реализации.
- Новый тест должен упасть до реализации — покажи вывод.
- Утверждённые тесты не меняй без согласования.
- Проверяй результат, а не внутренние вызовы.
- Один тест: vendor/bin/phpunit --filter ИмяТеста; весь набор: composer test.

Где TDD не работает

Не всё удобно начинать с теста. Вёрстку по макету проверяют глазами и скриншотами — об этом урок «Вёрстка по макету». Исследовательский прототип выбросят. Интеграции с внешним API, у которого нет тестового режима, сначала нужен контракт. В таких случаях работает облегчённый вариант: зафиксировать ожидаемое поведение хотя бы одним тестом после реализации, но до MR.

И последнее: зелёные тесты, написанные агентом, — ещё не доказательство, что поведение правильное. Проверка поведения остаётся одним из главных открытых вопросов агентной разработки; ему посвящён урок «Проверка поведения».

Попробуйте сами

10–15 мин на рабочем месте
  1. Возьмите небольшое бизнес-правило из текущей задачи и попросите агента написать только тесты. Найдите хотя бы один тест, не соответствующий правилу, или один пропущенный случай.
  2. Пройдите цикл «красный → зелёный» с запретом менять tests/. После реализации проверьте git diff --stat по каталогу тестов.
  3. После реализации добавьте тестовый случай, которого агент не видел, и посмотрите, проходит ли он.

Коротко

  • Тесты до кода — спецификация, которую агент не может истолковать по-своему.
  • Агент пишет тесты, вы их утверждаете — это главная точка контроля.
  • Красный тест должен падать из-за отсутствия реализации, а не из-за ошибки в тесте.
  • Реализация — без права менять утверждённые тесты; проверяйте дифф tests/.
  • Следите за подгонкой под тест, тотальными моками и тестами на внутренние вызовы.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX