урок 5 из 16

Тесты: что проверять и чем

Понимать, чем тест окупается теперь, отбирать проверяемое по цене ошибки, а не по проценту покрытия, различать три вида проверок по цене прогона и не допускать тестов, чьи ожидания списаны с кода.

17 мин чтения · 4 главы ·4 задания ·домашняя работа

Зачем тест, когда код пишется за минуту

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

Довод выглядит убедительно и разбивается ровно об одну таблицу.

РаньшеСейчаснаписать: полднянаписать: 5 минутпроверить: полчасапроверить: полчасапеределать: полдняпеределать: 5 минуттест окупался тем,что реже надо переделыватьтест окупается тем,что проверка становится дешёвойпеределка обесценилась, а проверка осталась на месте — вот и вся перемена
Раньше тест экономил время на переписывании. Теперь переписывание бесплатно, а проверка — нет.

Раньше тест окупался тем, что уменьшал количество переделок: полдня написания плюс полдня переделки — дорого, и тест, ловящий ошибку рано, экономил этот день. Теперь и написание, и переделка стоят по пять минут. Довод «тест экономит переделку» правда умер.

Но проверка не подешевела ни на минуту. Запустить, посмотреть на числа, проверить края, убедиться, что соседнее не сломалось, — это те же полчаса, что и десять лет назад. И вот тут тест и окупается: он превращает эти полчаса в три секунды, и превращает каждый раз, а не один.

Есть и второй довод, который стал важнее именно теперь. Правок стало в три раза больше — это прямое следствие ускорения написания. Каждая из них может задеть соседнее, и число «задеваний» растёт вместе с числом правок.

Раньше пять правок в неделю проверялись руками без особого труда. Пятнадцать правок в неделю руками уже не проверяются: на это уходит больше времени, чем на саму работу. Тест здесь не улучшение, а условие, при котором такая скорость вообще возможна.

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

И честная оговорка, без которой разговор получается пропагандой. Тесты бывают вредны — когда их пишут ради количества, когда они проверяют реализацию вместо поведения, когда их сто и они падают все разом от одной невинной правки. Такой набор не помогает, а берёт налог с каждой правки, и его справедливо ненавидят.

Разница между полезным и вредным набором проходит не по числу тестов, а по выбору того, что проверяется. Об этом вторая глава — и это самая содержательная часть темы.

Что проверять: три круга

Главный вопрос темы не «как писать тесты», а что именно проверять. Покрыть всё нельзя: набор вырастет больше кода и станет тем самым налогом.

Круг 1: то, где ошибка стоит денег или довериярасчёты, деньги, права, необратимое, обмен с чужими системамиКруг 2: то, что уже ломалоськаждая починка оставляет после себя тестКруг 3: то, что часто меняютправило отбора: не «покрыть побольше», а «где ошибка дороже»остальное проверяется руками и глазами, и это нормально
Покрыть всё нельзя и не нужно. Круги идут по убыванию цены ошибки, а не по устройству кода.

Отбор идёт по трём кругам, и порядок в них по убыванию цены ошибки.

Круг 1: где ошибка стоит денег или доверия. Расчёты, суммы, скидки, налоги, права доступа, необратимые действия, обмен с чужими системами. Здесь тесты нужны всегда, и здесь же они окупаются быстрее всего: ручная проверка расчёта — это подготовить данные, посчитать в уме и сравнить, то есть десять минут каждый раз.

Круг 2: то, что уже ломалось. Каждая починка оставляет после себя тест — это правило из прошлого урока, и оно же работает как способ отбора. Место, которое сломалось однажды, ломается снова: у него есть свойство, из-за которого это произошло, и свойство никуда не делось.

Круг 3: то, что часто меняют. Если файл правят каждую неделю, тест на него окупается за месяц. Если файл не трогали два года, тест на него — расход без дохода: он будет зелёным всегда и не поймает ничего.

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

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

И практический приём отбора, который экономит больше всего размышлений: напишите тест на то, что вы и так проверяете руками каждый раз. Если после правки расчёта вы открываете отчёт и смотрите на итоговую сумму — вот и тест. Он повторяет ваше движение, и потому точно проверяет то, что важно: важность уже подтверждена тем, что вы это делаете.

Три вида проверок и их цена

Проверки бывают трёх видов, и разница между ними — в том, сколько системы они поднимают.

Сквозная: весь путь, как у человекаминуты, хрупкая, ломается от чего угодно — берём единицыСтыковая: кусок с базой и соседямисекунды, надёжнее — берём десяткиОтдельная: одна функциямиллисекунды, стабильная — берём сотнивверху про «работает вообще», внизу про «считает верно»
Чем выше, тем дороже прогон и тем ближе к правде. Разумный набор опирается на нижний уровень.
ВидЧто проверяетЦена прогонаСколько брать
отдельнаяодну функцию с известными входамимиллисекундысотни
стыковаякусок вместе с базой и соседямисекундыдесятки
сквознаявесь путь, как у человекаминутыединицы

Отдельная проверка берёт функцию, даёт ей вход, сравнивает выход. Она быстрая, стабильная и точная: когда она падает, место известно сразу. Её слабость — она ничего не говорит о том, вызывается ли эта функция вообще и с теми ли данными.

Стыковая поднимает кусок системы: функцию вместе с базой, обработчик вместе с разбором запроса. Она отвечает на вопрос, которого не видит отдельная: сходятся ли части друг с другом. Большинство настоящих ошибок живёт именно на стыках, поэтому этот вид часто оказывается самым полезным на единицу усилий.

Сквозная проходит весь путь так, как его проходит человек. Она ближе всего к правде и хуже всего себя ведёт: медленная, зависит от всего сразу, падает от вещей, не имеющих отношения к делу. Держать их стоит единицы — на главные пути, те, поломка которых означает «система не работает».

Практическое правило выбора вида такое: берите самый дешёвый вид, который может поймать вашу ошибку. Ошибка в формуле ловится отдельной проверкой. Ошибка «забыли передать параметр в запрос» — только стыковой. Ошибка «кнопка не нажимается» — только сквозной.

Отдельно про скорость, потому что она решает больше, чем кажется. Набор, который идёт дольше двух минут, перестают запускать. Это не про дисциплину, а про то, как устроено внимание: две минуты ждут, десять минут — уходят делать другое и теряют нить.

И про надёжность. Тест, падающий через раз, надо чинить или удалять, третьего не дано. Такой тест обучает пропускать красный цвет, и обучает быстро: после третьего случайного падения человек перестаёт читать, что именно упало. Один ненадёжный тест обесценивает весь набор.

Причины случайных падений почти всегда в одном из трёх: тест зависит от времени, от порядка запуска или от данных, оставшихся от предыдущего прогона. Все три чинятся, и чинить их стоит сразу — они не рассасываются.

Тесты и агент: главная ловушка

Теперь про агента, и здесь есть одна ловушка, которая стоит всей главы.

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

Плохая новость — в том, откуда он берёт ожидаемый результат.

Такой тест бесполезен ровно в том случае, ради которого тесты и пишут: когда в коде есть ошибка. Он её закрепит и будет защищать. Более того, он сделает поведение труднее исправимым: попытка починить функцию уронит тест, и следующий человек решит, что чинить не надо.

Отсюда правило, простое и жёсткое: ожидаемый результат называет человек, а не код.

Что делает человекЧто делает агент
решает, что проверятьпишет проверки по названному списку
называет ожидаемый результатоформляет его как тест
перечисляет края, которые важныпишет проверки на каждый
читает упавший тест и решает, кто правпрогоняет и показывает разницу

Практически это выглядит так: вы говорите «на пустом списке должна быть ошибка, а не ноль; на одном элементе — он сам; на отрицательных — тоже ошибка», а он превращает это в код проверок. Числа и ожидания — ваши, оформление — его.

Есть и вторая ловушка, более тонкая. Агент склонен писать много мелких проверок на то, что легко проверить, — потому что это самая простая часть задачи. Получается двадцать тестов на разбор строки и ни одного на главный расчёт, который сложнее сформулировать.

Лечится это тем же способом, что и первая: список того, что проверять, приносите вы. Три круга из второй главы — и есть этот список.

Наконец, про починку упавших тестов, потому что здесь прячется самая дорогая ошибка. Когда тест падает, есть два объяснения: сломался код или устарел тест. Выбор между ними — решение, и принимать его должен человек.

Поручение «тесты падают, почини» почти всегда приводит к тому, что подгоняются тесты: это короче, чем разбираться в коде, и результат выглядит одинаково — всё зелёное. Правильное поручение другое: «тест упал; покажи, что изменилось в поведении». Дальше вы решаете, было ли это изменение намеренным.

Задания урока

Каждое проверяется сразу: ответ сверяется с эталоном, и на неверный вариант приходит разбор.

  1. Раз код теперь пишется за минуту, тесты стали не нужны.средне
  2. Разложите, что стоит покрывать тестами, а что нет.средне
  3. Расставьте виды проверок от самой дешёвой к самой дорогой.средне
  4. Тест, написанный агентом по коду, проверяет правильность поведения.сложно

Практика и материалы по теме курса

Пройти урок с проверкой заданий Курс «Codex: продукты и практика» открыт и бесплатен, прогресс сохраняется.
Открыть курс