Тест как ТЗ для агента
Сцена · ТЗ на языке примеров
Представь, что ты заказываешь функцию подрядчику. Можно написать абзац прозы: “разбери строку рубли точка копейки в целое число копеек”. А можно положить таблицу:
| вход | выход |
|---|---|
"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.