Раздел 29 · Тестирование

Тест как ТЗ для агента

middle~45 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

Тест как ТЗ для агента

Сцена · ТЗ на языке примеров

Представь, что ты заказываешь функцию подрядчику. Можно написать абзац прозы: “разбери строку рубли точка копейки в целое число копеек”. А можно положить таблицу:

входвыход
"0.00"0
"12.34"1234
"100.05"10005

Вторая форма короче, не допускает разночтений и, главное, исполняема: её можно прогнать и проверить. Это и есть центральная идея блока. Тест это спецификация, которая сама себя проверяет. А подрядчик у тебя теперь часто не человек, а агент.

Карта урока · что заберёшь

  • поймёшь, почему таблица “вход, выход” это лучшее ТЗ для агента;
  • научишься писать тест, который задаёт поведение, а не подсказывает реализацию;
  • увидишь, как неоднозначное ТЗ расходится в две разные реализации;
  • освоишь петлю “таблица, агент, red/green, уточнение” как рабочий ритм.

Раздел 1 · почему тест это лучшее ТЗ

Сцена

Ты уже знаешь из урока про то, что тестировать, что проверять надо поведение через публичный API, а не детали реализации. Теперь развернём это в рабочий процесс: сначала ты фиксируешь поведение примерами, и только потом появляется код. Неважно, твой это код или агента.

Идея словами

Спецификация на примерах точнее прозы по простой причине: проза описывает намерение, а пример описывает результат. Агент читает намерение и достраивает детали по своему усмотрению. Пример не оставляет ему свободы: либо parseAmount("12.34") равно 1234, либо нет.

Хорошее ТЗ для агента это три вещи разом:

  • конкретные входы и выходы, а не “должно корректно обрабатывать суммы”;
  • покрытые границы: ноль, максимум, пустое, неверный формат, а не только happy-path;
  • никаких деталей реализации в проверке: ты говоришь, что вернуть, а не как считать.

Картинка · таблица как ТЗ

Переключи трактовку между агентом A и агентом B. Пока в таблице нет строки про "12.5" (одна цифра копеек), оба зелёные: ТЗ про этот случай молчит, и агенты ведут себя по-разному, но ты этого не видишь. Нажми “добавить строку”: теперь ТЗ требует отвергать одну цифру копеек, и догадливый агент B краснеет. Один тест сделал расхождение видимым.

Шаг 1 · таблица превращается в тест

Таблицу из сцены переносим в код один в один. Это и есть форма табличного теста из урока 06:

// packages/ledger/test/amount.test.ts
import { describe, expect, it } from 'vitest';

import { parseAmount } from '~/index.ts';

describe('parseAmount как ТЗ', () => {
  it.each([
    { input: '0.00', expected: 0 },
    { input: '12.34', expected: 1234 },
    { input: '100.05', expected: 10005 },
  ])('parseAmount("$input") равно $expected', ({ input, expected }) => {
    expect(parseAmount(input)).toBe(expected);
  });
});

Это red-фаза: реализации ещё нет, тест красный. Теперь у агента есть точное задание.

Шаг 2 · границы это часть ТЗ

Happy-path агент закроет и без тебя. Ценность ТЗ в границах. Допиши строки, которые задают поведение на краю:

it.each([
  { input: '', reason: 'пустая строка' },
  { input: '12', reason: 'нет копеек' },
  { input: '12.5', reason: 'одна цифра копеек' },
  { input: '12.345', reason: 'три цифры копеек' },
])('parseAmount("$input") отвергает: $reason', ({ input }) => {
  expect(() => parseAmount(input)).toThrow();
});

Чего ты не потребовал, того агент не покроет. Граничная строка в таблице это и есть требование.

Когда код пишет агент

Дай агенту только happy-path, и получишь реализацию, которая разваливается на "12.5": он выбрал свою трактовку и сделал её молча. Дай таблицу с границами, и трактовка станет твоей. ТЗ это не “напиши parseAmount”, ТЗ это таблица, в которой границы прописаны явно.

Что взять с собой

  • таблица “вход, выход” точнее прозы, потому что исполняема;
  • ценность ТЗ в границах, а не в happy-path;
  • it.each превращает таблицу в набор именованных тестов.

дальше после входа

Урок целиком открыт всем, кто вошёл. Войди по своему email, чтобы читать дальше.

Вход пока по приглашению. Если хочешь учиться, напиши Vassiliy.