Сначала решите проблему, затем напишите тесты, затем напишите код

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

Как я использую код

До TDD большая часть моей разработки заключалась в следующем:

  1. Команда получает список заявок Jira, над которыми нужно работать.
  2. Команда выполняет поставленные задачи без каких-либо тестов и выполняет тестирование разработчика, проверяя, соответствует ли код критериям приемлемости задач.
  3. Запросы на вытягивание проходят проверку кода.
  4. PR объединяется, а затем QA выполняет ручное / автоматическое тестирование.
  5. Есть несколько раундов исправления ошибок и тестирования QA.
  6. Код перемещен в производство.

По своему опыту могу сказать, что, когда у команд нет хорошего, хорошо написанного набора тестов для написанного кода, среднее время производства для задач продолжает расти вместе с кодовой базой. Существуют такие принципы, как SOLID-дизайн, которые могут помочь вам сохранить ваш код менее связным и более связным, но в конечном итоге без хорошего набора тестов сложность добавления новых функций продукта и поддержки текущих функций будет продолжать расти. в небольшом темпе и, в какой-то момент, в конечном итоге сильно замедлит процесс разработки / выпуска.

Вот где поговорка «Медленно - быстро» в разработке программного обеспечения терпит неудачу, потому что без хорошего набора тестов по мере увеличения размера кодовой базы становится действительно сложно и обременительно проверять влияние любых изменений на всю кодовую базу. Эти воздействия могут быть пропущены инженерами по обеспечению качества и могут проникнуть в производственную среду. Если QA-инженеры улавливают воздействия, упущенные разработчиками, среднее время исправления увеличивается и прибавляется к нескольким дополнительным раундам тестирования.

TDD приходит на помощь

Разработка через тестирование (TDD) - это« процесс разработки программного обеспечения , основанный на повторении очень короткого цикла разработки: требования превращаются в очень конкретные тестовые примеры. , Затем программное обеспечение улучшается, чтобы тесты прошли».

Давайте рассмотрим пример. Представьте, что разработчик получил билет на исправление, в котором он должен изменить формат даты с MMM DD, YYYY HH: mm A (10 августа 2019 г., 20:30) на MMM DD, YYYY (10 августа 2019 г.). Эти форматы взяты из документации moment.js.

Разработчик выяснил, что дата форматируется функцией formatShortDate , которая выглядит так:

export const formatShortDate = (value) => {
    if (_.isEmpty(value)) return ''
    return moment.utc(value).local().format('MMM DD, YYYY HH:mm A')
}

Разработчик изменил его на:

export const formatShortDate = (value) => {
    if (_.isEmpty(value)) return ''
    return moment.utc(value).local().format('MMM DD, YYYY')
}

Изменение было однострочным, поэтому оно было развернуто в производственной среде и устранило проблему. После этого развертывания другой компонент, который отображает ежедневное расписание пользователя с 9:00 до 18:00, теперь не работает, и пользователи видят дату без времени. Поэтому требуется еще одно исправление.

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

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

Тестовый пример, который может захватить сломанный компонент (я считаю, что компонент является компонентом Vue), может быть следующим:

В тот момент, когда разработчик изменит формат с 'MMM DD, YYYY HH: mm A' на 'MMM DD, YYYY', оба описанных выше тестовых примера не пройдут, и разработчик узнает, что изменение нарушает UserScheduleWidget и затем можно будет предпринять необходимые корректирующие действия.

Жизненный цикл TDD

  1. Красный: сначала напишите тестовый пример и позвольте ему потерпеть неудачу.
  2. Зеленый: напишите достаточно кода, чтобы пройти тест.
  3. Рефакторинг: оптимизируйте код для текущего теста.

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

Что я узнал

TDD помогает сократить время разработки

Вы можете возразить, что если мы пишем тестовый код больше, чем код реализации, то как сокращается время разработки. Что ж, корпоративные проекты - это не шестимесячные проекты, кодовая база продолжает развиваться с добавлением новых функций, и при этом среднее время создания функции продолжает увеличиваться с увеличением количества ошибок на процент функции. Именно здесь TDD помогает держать оба вышеуказанных показателя под контролем или почти на постоянном уровне. Таким образом, эта первая стратегия тестирования может первоначально привести к замедлению времени разработки на 10–20%, но преимущества, полученные на более поздних этапах проекта, обычно через год, помогают сократить время разработки в дальнейшем и помогают сохранить сложность кода проекта. низкий.

TDD сделал меня лучшим разработчиком

Прежде чем писать какой-либо код реализации, вы должны сначала написать для него модульный тест. Модульные тесты работают изолированно, и вы имитируете внешние зависимости. При наличии некоторого ввода тестируемая единица кода должна выдавать известные выходные данные. Если да, то проходит. В противном случае тест не пройден. Этот аспект написания тестируемого модульного кода помог мне понять, как разбивать большие компоненты на небольшие части тестируемого кода, что является важной частью композиции и разделения программного обеспечения. Если вы пишете действие, у вас должна быть возможность сначала выполнить его модульное тестирование без рендеринга компонента. Если вы пишете компонент пользовательского интерфейса, вы должны иметь возможность сначала провести его модульное тестирование, фактически не загружая компонент пользовательского интерфейса в браузере, и TDD поможет вам в этом. Таким образом, эта стратегия «сначала тестирование» поможет вам стать лучшим разработчиком.

TDD помогает быстрее отлаживать

Когда вы пишете тест, который запускает код для фактической реализации, тогда тесты проходят, только если код соответствует утверждениям в тесте. Если вы измените реализацию, утверждения в тесте не будут выполнены. Таким образом, зная, какие тесты завершаются ошибкой, вы можете легко перейти к ошибочному коду и приступить к исправлению. Без TDD отладка становится проблемой, и вам придется потратить много времени на стандартные способы отладки, такие как установка точек останова в инструментах разработчика или добавление console.log в код. Таким образом, TDD упрощает отладку.

TL; DR

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

Если вам понравился этот материал, я бы хотел, чтобы вы нажали кнопку хлопка 👏 , чтобы другие могли наткнуться на него

«Долг ученых - следить за тем, чтобы племя благородных людей продолжало расти.» - Атхарва Веда