Тдд: Что Пошло Не Так?

Данная статья представляет собой перевод материала «TDD: Что пошло не так или случилосьЭ» Разработка через тестирование (TDD) уже давно получила признание в индустрии разработки программного обеспечения.

Однако в последнее время о TDD было сказано много резких слов, поскольку его обвиняли в плохом дизайне программного обеспечения и невыполнении многих своих обещаний.

Кульминацией этой тенденции стал пост Дэвида Хайнемейера Ханссона.

«TDD мертв.

Да здравствует тестирование».

(TDD мертв.

Да здравствует тестирование).

Как возможно, что одна и та же техника, столь полезная для стольких разработчиков, оказывается столь губительной для других? В этой статье Владислав Кононов расскажет о трех заблуждениях, которые могли бы объяснить этот феномен.

Начнем с самого тонкого и разрушительного.



TDD — это не проектирование через тестирование

TDD означает разработку через тестирование.

К сожалению, многие люди ошибочно интерпретируют это как «проектирование через тестирование».

Эта неточность может показаться невинной, но поверьте, это не так.

Позволь мне объяснить.

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

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

Истинная цель – выполнить проекты вовремя, в рамках бюджета и, самое главное, в соответствии со всеми требованиями качества.

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

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

Он будет напоминать огромный граф объектов, полный случайных сложностей.

но его можно будет протестировать.

Протестировано тестами, которые тонут в макетах (имеется в виду макет как тестовый дубль) и полностью ломаются после изменения одной части реализации.

Это то, что называется «повреждениями, вызванными испытаниями», и это наглядно показано в блоге Дэвида Хайнемейера Ханссона.

«TDD мертв.

Да здравствует тестирование».

:

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

Я не думаю, что это здорово.

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

Например, попасть в базу данных.

Или файл IO. Или зайдите через браузер, чтобы протестировать всю систему.

Это привело к появлению поистине ужасающих архитектурных чудовищ.

Густые джунгли сервисных объектов, шаблонов команд и многого другого.

Должен быть? Ваша сфера деятельности должна определять ваши дизайнерские решения.

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

Нет смысла полностью модели предметной области если все, что вам нужно, это обычный интерфейс CRUD - вместо этого реализуйте шаблон Активная запись .

Если вам нужен только сценарий ETL, используйте шаблон Скрипт транзакции .

Как вообще может иметь смысл решать все проблемы с помощью одного и того же решения — гексагональной архитектуры и модели предметной области? «Потому что этот дизайн идеально подходит для модульных тестов!» Ясно.

Пришло время поговорить о втором заблуждении.



TDD — это не (только) модульные тесты.

Существует широко распространенное мнение, что если вы используете TDD, вам следует писать модульные тесты.

Это не имеет никакого смысла.

Юнит-тесты — это не волшебное средство, и, кстати, если вы посмотрите на определение ТДД В Википедия , вы ничего не найдете о модульных тестах:

Разработка через тестирование (TDD) — это процесс разработки программного обеспечения, основанный на повторении очень короткого цикла разработки: сначала разработчик пишет (изначально неудачный) автоматизированный тестовый сценарий, который определяет желаемое улучшение или новую функцию, затем создает минимальный объем кода.

пройти этот тест и, наконец, преобразовать новый код в приемлемые стандарты.

Основное внимание уделяется автоматизированным тестам, и их можно разделить на три типа: модульные тесты, интеграционные тесты и сквозные тесты.

Я не верю, что каждому проекту нужен каждый из них.

Опять же, это решение должно определяться вашей проблемной областью:

  1. Вы имеете дело со сложной бизнес-логикой? Здесь действительно нужны модульные тесты.

  2. Вы выполняете только простые операции CRUD? Используйте интеграционные тесты или сквозные тесты.

  3. ETL-скрипт? Достаточно сквозных тестов.

Выберите стратегию тестирования, которая лучше всего подходит для вашего домена.

Сначала напишите свои тесты, и вуаля — вы используете TDD и не позволяете тестам разрушить ваш дизайн.

.

И если говорить о юнит-тестах, что вообще такое юнит? Перейдем к третьему заблуждению.



Единица != Класс

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

Такой подход является неточным.

Это рецепт сильной связи между тестами и реализацией.

Эти отношения подорвут все ваши усилия по рефакторингу, тем самым нарушив одно из фундаментальных обещаний TDD. Определение модуля, которое мне нравится больше всего, Рой Ошеров , автор книги Искусство модульного тестирования :

Модульный тест — это автоматизированный фрагмент кода, который вызывает единицу работы в системе, а затем проверяет одно предположение о поведении этой единицы работы.

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

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

Функциональные тестовые примеры отделяют тесты от реализации.

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



Отсутствует D в TDD

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

Принято считать, что хорошо спроектированный код также поддается тестированию.

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

Доказательство тривиально:

  • Как идентифицировать тестируемый код? Это легко, в зависимости от того, есть тесты или нет.
  • Как оценить качество дизайна? Извините, здесь нет ярлыков — все зависит от контекста.

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

    А чрезмерное усложнение одной области – это небрежность к более сложной.

Следовательно, даже если реализация поддается тестированию, она все равно может не подходить для решаемой проблемы и предметной области бизнеса.

Следовательно, недостающая буква «D» в TDD — это «домен» бизнеса/проблемы.

Вот почему я считаю, что DDD является необходимым условием для разработки через тестирование.

Методология DDD применима не только к сложным моделям предметной области — напротив, она определяет набор рекомендаций по выбору лучшего инструмента для работы в соответствии с проблемной предметной областью.

Но это тема совсем другой статьи.



P.S. ТДД 2.0

TDD был «заново открыт» Кентом Беком более десяти лет назад. Возможно, пришло время заново открыть для себя TDD. Помимо модульных тестов, новая спецификация должна охватывать другие типы автоматических тестов, которые в то время были недоступны.

И, конечно же, вместо того, чтобы бороться с этим, TDD следует тесно сотрудничать с бизнес-сферой.

Теги: #программирование #Анализ и проектирование систем #Тестирование ИТ-систем #проектирование и рефакторинг #автоматическое тестирование #tdd #юнит-тестирование #юнит-тесты

Вместе с данным постом часто просматривают: