Первые тесты

качество≈ 6 минут

Здесь будет встроен видео-разбор темы (5–7 минут, YouTube / RuTube / VK Видео) — тем, кто лучше воспринимает на слух, текст ниже не обязателен.

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

Разделы темы:·

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

У тестов две роли. Первая — страховка: меняете код сколько угодно, запускаете тесты и сразу видите, что уцелело, а что нет. Вторая — спецификация: набор тестов читается как список обещаний «эта функция ведёт себя вот так». Тест описывает поведение честнее комментария: устаревший комментарий молчит, а устаревший тест проваливается.

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

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.
разбор вывода
true — тест пройден. Появился false — ожидание и реальность разошлись, и это ровно тот момент, ради которого тесты пишут.

Не хватает одного: чтобы провал нельзя было проглядеть в потоке вывода. Для этого есть инструмент получше голого console.log.

Метод console.assert(условие, сообщение) работает как строгий, но немногословный проверяющий. Условие истинно — он молчит. Условие ложно — печатает в консоль ошибку с вашим сообщением.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Обратите внимание на две вещи. Успешные проверки не засоряют консоль — видны только провалы. И проваленный assert не останавливает скрипт: выполнятся и все остальные проверки, так что за один запуск вы получаете полную картину.

Напишем функцию pow(x, n), возводящую x в натуральную степень n, и сначала просто посмотрим на неё глазами.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

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

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Тишина перед финальной строкой — это и есть успех. Теперь у pow есть страховка: если кто-нибудь «оптимизирует» цикл и ошибётся, тесты закричат при следующем же запуске.

В настоящих проектах тесты пишут не на console.assert, а с помощью тест-фреймворков — самые популярные сегодня Jest и Vitest. Внутри — то же сравнение ожидания с фактом, но с удобствами: тесты живут в отдельных файлах, у каждого есть человекочитаемое название, а после запуска печатается отчёт — сколько прошло, сколько упало и где именно. Устанавливать их сейчас не нужно: главное, что идея внутри ровно та, которую вы уже освоили.

Во фреймворках проверка выглядит как expect(факт).toBe(ожидание). Звучит солидно, но простейшую версию такой конструкции можно написать за минуту.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

С чего начинать проверки? Правило простое: сначала обычные случаи — типичные аргументы, ради которых функция и написана. Потом граничные — значения на краях допустимого: ноль, отрицательные числа, пустая строка. Обычные тесты ловят «функция вообще не работает», граничные — «функция работает, но не всегда».

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Граница нашла баг: при отрицательной степени цикл не выполняется ни разу, и функция возвращает 1 вместо 0.5. Все три «обычных» теста из раздела про pow этого не заметили бы никогда. Дальше два честных пути: починить функцию — или договориться, что она работает только при n >= 0, и зафиксировать это отдельным тестом.

Тип данныхГраничные значения для проверки
Числа0, отрицательные, очень большие
Строкипустая "", один символ, строка из пробелов
Массивыпустой [], один элемент
«Ничего»undefined, null

Мнемоника границ: ноль, минус, пусто

  • Тест сравнивает ожидание с фактом: совпали — код ведёт себя как задумано.
  • console.assert(условие, сообщение) молчит при истине, печатает сообщение при лжи и не останавливает скрипт.
  • Тесты — страховка при изменениях: после любой правки перезапустите их и сразу узнаете, что сломалось.
  • Фреймворки вроде Jest и Vitest — те же проверки плюс отчёты и удобства; идея внутри не меняется.
  • Порядок кейсов: сначала обычные, потом граничные — ноль, отрицательные, пустые значения.

1/3Что появится в консоли после console.assert(5 > 3, "ошибка")?

2/3Функция pow из статьи (версия с циклом) — что вернёт pow(2, -3)?

3/3Тест через console.assert провалился. Что происходит со скриптом?

Допишите isEmpty

Напишите функцию isEmpty(str), которая возвращает true для пустой строки и false для любой другой. Тесты уже готовы — ваша задача заставить их замолчать.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Достаточно одного сравнения: return str === "";. После этого оба console.assert перестанут выводить ошибки — тишина и есть успех.

Поймайте баг границей

Функция firstChar возвращает первый символ строки. На обычных строках она работает, но один граничный случай выдаёт undefined. Напишите console.assert, фиксирующий желаемое поведение — для пустой строки пусть возвращается пустая строка, — и почините функцию.

js
Tab добавляет отступ. Чтобы выйти из редактора, нажмите Escape — фокус перейдёт на кнопку запуска.

Тест: console.assert(firstChar("") === "", "пустая строка");. Починка: return str.length > 0 ? str[0] : ""; — граница закрыта и закреплена тестом навсегда.