Садись интернет, это интервенция

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

Совершенно ужасный пример

Это было для меня. Соломинка не только сломала спину моему верблюду, но и ударила его по морде. Смотреть:

const convertTimestamp = (timestamp) => {
  try{
    return timestamp.toIsoString()
  catch (e) {
    logger.error(`We goofed: ${e.toString()}`);
    return '';
  }
}

const formatMessageObj = (rawMessage) => {
  const { 
    id,
    name, 
    created_at: created,
    session_start_time: sessionStart, 
    timestamp,
    session_users: users,
  } = rawMessage;
  return {
    id,
    created,
    sessionStart,
    users,
    timestampISO:  convertTimestamp(timestamp),
  }
}

Несколько удобных маленьких помощников, в этом нет ничего плохого. Это что, 25 строк? Если честно, не так много логики, кроме метки времени. Я хочу, чтобы вы угадали, сколько строк кода было в тестах.

176 строк.

Ты шутишь, что ли? Потребовалось почти 200 строк, чтобы перепроверить, не переименовали ли мы свойства? Один из тестов проверял, может ли этот код обрабатывать как полные, так и пустые массивы session_users. Что? Нет логики! Это просто точное копирование свойства . Если бы session_users было строкой адреса NFT, этот код все равно скопировал бы ее.

Кикер

Я все же взломал код. При изменении сообщения об ошибке я нажал лишнее } в шаблоне строки и испортил распечатку. Это сообщение об ошибке в 176 строках тестов никогда не проверялось. Эта функция состоит из 6 строк, и мы все же умудрились пропустить одну. 176 строк тестов.

Катапультировать мое тело на проклятое солнце.

Маскировка проблем

Не могуповерить, что говорю это, но в некоторых случаях я бы предпочел непроверенный код избыточным модульным тестам. Уф, как я уже сказал, маленькая часть моей души просто разбилась. Но это правда. И я скажу вам почему: ложное чувство безопасности может быть опасным. Опять же, для этого раздела кода было около 200 строк теста для примерно 300 строк кода. Это кажется, может быть, немного легким, но не жестоким. Или я так думал.

Я был дураком, абсолютным куклой. Если бы я читал повнимательнее, я увидел бы ложь. Из 300 строк реального кода всего 21 функция. Мы тестировали только 4 из них. 4! Я только что перечислил 2, остальные тоже чисто вспомогательные функции. Знайте, что этот сервис имеет внутреннее соединение с базой данных, интеграцию с DataDog, внешний сервис БД и опирается на общую библиотеку. Разве это не полезно проверить? Из-за этого инцидента автоматически создаваемые отчеты о покрытии кода являются таким важным инструментом.

Первый шаг — признать, что у нас есть проблема

Нет ничего плохого в модульных тестах, естьчто-то неправильное в тольконаличии модульных тестов, особенно плохих. Более интенсивные моки и интеграционные тесты сложнее писать и поддерживать (особенно моки), но если все сделано хорошо, они всегда того стоят.

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

«Это займет слишком много времени, чтобы справиться с интеграционным тестированием»
«Мы проверим, когда этот MVP заработает»
«Просто выберите счастливый путь»
«Cypress — это круто, мы должны сделать это когда-нибудь. Не сегодня, очевидно, но когда-нибудь».

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

Как это исправить?

Честно говоря, все сводится к простой идее: боритесь за время,которое требуется для написания тестов, которые вселяют в вас уверенность. Любая новая функция должна быть полностью протестирована. Делая это, вы, вероятно, добавите более качественные тесты и, вероятно, некоторые утилиты для тестирования. Вы сможете добавить более лаконичные и легко копируемые шаблоны тестирования. И затем, после нескольких полностью охваченных функций, у вас будет набор новых инструментов и методов для использования. Теперь, с вашим новым арсеналом знаний и утилит, возвращение и добавление/рефакторинг старых тестов должно быть намного проще.

Как вы проводите новые тесты, не имеет значения. Используйте любой фреймворк и методы, какие захотите (можно даже использовать полный TDD, хотя я скептически отношусь к большинству реализаций там). С новыми тестами сосредоточьтесь на качестве, а не на количестве. Если вы поджимаете сроки, давление будет отстойным. Но хорошее тестирование в конечном итоге ускоряет вас в долгосрочной перспективе. Надежный набор тестов дает вам уверенность при добавлении и рефакторинге функций.

Модульные тесты — это удивительный инструмент, легко составляющий основу любого хорошего набора тестов. Но они не могут сделать это в одиночку. Потратьте время, чтобы добавить больше интегрированных и углубленных тестов, и вы будете на 1000 % лучше.

всем удачного кодирования,

Майк