Как снова сделать TDD отличным

Как и все, что называется Agile, разработка через тестирование (TDD) - это то, что в теории звучит великолепно. На практике непонятно, как это правильно делать. Вам часто говорят, что если вам это не нравится, вы делаете это неправильно. Неудивительно, что большинство разработчиков, которых я встречал, смогли объяснить преимущества использования TDD, в то время как никто из них не использовал его в своей работе. Ни одного.

В последнее время раздаются голоса против TDD, обвинения в том, что она не стоит усилий, и невыполнения многих своих обещаний. Некоторые даже заявляют, что TDD мертв. Как может что-то столь выгодное быть настолько нежелательным для разработчиков?

В этой статье я хочу поговорить о четырех основных проблемах TDD на практике, которые объясняют это явление.

Проблема 1: рефакторинг ломает многие тесты

Если мы немного изменим код реализации, ни один из тестов не сломается. Это одно из обещаний, которые дает TDD. На практике ломается как минимум тысяча тестов. Произошло то, чего не должно было случиться. Чтобы исправить это, мы часто переписываем наш тестовый код, а не реорганизуем его. Мы тратим гораздо больше времени на написание тестового кода, чем на код реализации.

В конце концов, мы сомневаемся, стоит ли переписывать тестовый код, если мы уверены, что проведем рефакторинг кода реализации. Можем ли мы написать меньше тестов? Можем ли мы пропустить все тесты? Затем кто-то предложит написать тесты, когда будут внесены все изменения, как за день до релиза. На практике это часто бывает после релиза или никогда.

Проблема 2: написать больше тестового кода, чем кода реализации

Чтобы протестировать «единицу» кода реализации, мы часто пишем тесты для всех общедоступных методов и пишем макеты для зависимостей. Иногда мы делаем частные методы общедоступными, потому что в противном случае невозможно увеличить покрытие кода. Мы создаем тестовые примеры, чтобы охватить как можно больше различных потоков кода реализации.

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

Проблема 3: Red-Green-Refactor побуждает писать плохой код

Вкратце, Red-Green-Refactor означает:

  1. Напишите тест, который не проходит или даже не компилируется
  2. Напишите достаточно кода реализации, чтобы пройти тест
  3. Рефакторинг кода реализации

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

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

Это разрушает наши ценности как разработчиков. Это практически нарушение этики программирования, незаконное и непрофессиональное.

Проблема 4: измерение покрытия кода

Это старая поговорка: «Что измерить, то делается». Если качество измеряется по покрытию кода, разработчики будут стараться изо всех сил удовлетворить это минимальное требование к покрытию кода. Если нам не разрешат отгружать, когда покрытие кода ниже 85%, мы в конечном итоге будем добавлять все больше и больше тестов, обычно тех, которые проще всего создать, чтобы достичь чуть более 85% и не более. Как ни странно, большинство этих тестов тривиальны и не имеют особой ценности для обеспечения качества. Это заставляет разработчика сосредоточиться на поиске способов создания некачественных тестов только для достижения минимального уровня покрытия кода.

Делаем TDD снова отличным

В некоторых проблемах могут быть виноваты учебные материалы по TDD. Большинство из них сосредоточено на чрезмерно упрощенных примерах, таких как:

  • Добавление двух целых чисел
  • Объединить строки
  • FizzBuzz

В этих примерах часто неясно, как должен выглядеть модульный тест в TDD. Как протестировать приложение Spring Boot? А как насчет тестирования объектно-ориентированного кода? Разработчики склонны полагать, что им необходимо тестировать каждую «единицу» своего кода - каждый общедоступный метод. Это означает следующие проблемы при таком подходе TDD:

  • Больше тестового кода, чем кода реализации
  • Нелегко разработать тесты до завершения реализации
  • Рефакторинг реализации ломает существующие тесты

Кент Бек объяснил в своей книге Разработка через тестирование: на примере, что модульные тесты в TDD должны проверять поведение, а не реализации. Спустя почти 20 лет большинство статей о TDD забыли об этой первоначальной идее. Разработчики часто заходят слишком далеко, пытаясь написать тесты для всего. Видя, что его идея вызвала столько путаницы, и люди начали жаловаться на свою боль, используя TDD, Кент Бек уточнил, как он будет использовать модульные тесты для.

Другими словами, мы должны протестировать поведение нашей программы или границы «API» внутри нашей программы. «Единица» обычно относится к одному значимому поведению в нашей разработке программного обеспечения, а не к реализации программного обеспечения. Это решает проблемы 1, 2 и 3, указанные выше, потому что реализации часто меняются во время разработки, но не поведение.

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

TDD как привычка

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

Затем, через неделю или две, как раз когда болезненные ощущения вот-вот пройдут, приближается крайний срок проекта. Каждый час бодрствования нужно тратить на то, чтобы выполнить значимую работу, поэтому вы отбрасываете ненужные вещи, например, походы в спортзал. Сейчас дедлайн закончился, но вы отвыкаете. Если вам вообще удастся вернуться в спортзал, вы почувствуете такую ​​же боль, как и в первый раз.

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

Теперь начните практиковать TDD в своей работе, а если сомневаетесь, прочтите книгу еще раз.