Я пытаюсь обернуть голову вокруг TDD, особенно в части разработки. Я посмотрел некоторые книги, но те, которые я нашел, в основном касаются части тестирования - История NUnit, почему тестирование хорошо, Red / Green / Refactor и как создать String Calculator.
Хорошие вещи, но это "просто" модульное тестирование, а не TDD. В частности, я не понимаю, как TDD помогает мне получить хороший дизайн, если мне нужен дизайн, чтобы начать его тестирование.
Для иллюстрации представьте эти 3 требования:
- Каталог должен иметь список продуктов
- Каталог должен помнить, какие продукты просматривал пользователь
- Пользователи должны иметь возможность искать продукт
На этом этапе многие книги вытаскивают волшебного кролика из шляпы и просто погружаются в «Тестирование ProductService», но они не объясняют, как они пришли к выводу, что это ProductService. Это та часть «развития» в TDD, которую я пытаюсь понять.
Должен быть существующий дизайн, но ничего за пределами сущностных сервисов (то есть: существует Продукт, поэтому должен быть ProductService) нигде не найти (например, второе требование требует от меня иметь некоторую концепцию Пользователь, но куда мне поместить функцию напоминания? И является ли функция поиска компонентом ProductService или отдельным SearchService? Как узнать, какой вариант выбрать?)
Согласно SOLID , мне потребуется UserService, но если я спроектирую систему без TDD, у меня может получиться целый набор Single-Method Services. Разве TDD не предназначен, чтобы заставить меня открыть мой дизайн в первую очередь?
Я разработчик .net, но ресурсы Java тоже подойдут. Я чувствую, что, похоже, нет реального примера приложения или книги, которые бы касались реального направления бизнес-приложений. Может ли кто-нибудь привести наглядный пример, иллюстрирующий процесс создания дизайна с использованием TDD?
Ответы:
Идея TDD - начать с тестирования и работать с этого. Таким образом, для примера «Каталог должен иметь список продуктов» можно рассматривать как тест «Проверка продуктов в каталоге», и, таким образом, это первый тест. Теперь, что держит каталог? Что держит продукт? Это следующие части, и идея состоит в том, чтобы собрать воедино несколько кусочков, которые были бы чем-то вроде ProductService, который будет рожден после прохождения первого теста.
Идея TDD - начать с теста, а затем написать код, который делает этот тест успешным в качестве первого пункта. Модульные тесты - это часть этого «да», но вы не смотрите на общую картину, которая формируется, начиная с тестов, а затем писать код, чтобы в этот момент не было слепых зон, поскольку кода еще нет.
Test Driven Development Tutorial, где слайды 20-22 являются ключевыми. Идея состоит в том, чтобы узнать, что функциональность должна делать в результате, написать тест для нее и затем построить решение. Часть дизайна будет варьироваться в зависимости от того, что требуется, это может или не может быть так просто сделать. Ключевой момент заключается в том, чтобы использовать TDD с самого начала, а не пытаться вводить поздно в проект. Если вы начнете с тестов в первую очередь, это может помочь и, вероятно, в некотором смысле стоит отметить. Если вы попытаетесь добавить тесты позже, это может быть отложено или отложено. Более поздние слайды также могут быть полезны.
Основным преимуществом TDD является то, что начиная с тестов, вы изначально не привязаны к дизайну. Таким образом, идея состоит в том, чтобы создать тесты и создать код, который пройдет эти тесты в качестве методологии разработки. Big Design Up Front может вызвать проблемы , так как это дает представление о фиксации вещи на место , что делает создаваемую систему менее ловкими в конце концов.
Роберт Харви добавил это в комментариях, которые стоит отметить в ответе:
источник
Для чего это стоит, TDD помогает мне прийти к наилучшему дизайну гораздо быстрее , чем не делать TDD. Я, вероятно, пришел бы к лучшему дизайну с или без него. Но то время, которое я бы потратил на то, чтобы обдумать это и сделать несколько попыток, потратило время на написание тестов. И времени меньше. Для меня. Не для всех. И даже если бы это заняло такое же количество времени, это оставило бы меня с набором тестов, так что рефакторинг был бы более безопасным, что привело бы к еще лучшему коду.
Как это сделать?
Во-первых, это побуждает меня думать о каждом классе как о сервисе для некоторого клиентского кода. Лучший код получается от размышлений о том, как вызывающий код хочет использовать API, а не от того, как должен выглядеть сам код.
Во-вторых, это мешает мне писать слишком много циклометической сложности в одном методе, пока я обдумываю это. Каждый дополнительный путь через метод будет иметь тенденцию удваивать количество тестов, которые мне нужно сделать. Сама лень диктует, что после того, как я добавил слишком много логики, и мне нужно написать 16 тестов, чтобы добавить одно условие, пришло время вывести некоторые из них в другой метод / класс и протестировать их отдельно.
Это действительно так просто. Это не волшебный инструмент дизайна.
источник
Эти требования должны быть пересмотрены с точки зрения человека. Кто хочет знать, какие продукты ранее просматривал пользователь? Пользователь? Продавец?
Как? По имени? По бренду? Первым шагом в разработке через тестирование является определение теста, например:
>
Если бы это были единственные требования, я бы не стал прыгать, чтобы создать ProductService. Я мог бы создать очень простую веб-страницу со статическим списком товаров. Это будет работать идеально, пока вы не получите требования для добавления и удаления продуктов. В этот момент я могу решить, что проще всего использовать реляционную базу данных и ORM и создать класс Product, сопоставленный с одной таблицей. По-прежнему нет ProductService. Такие классы, как ProductService, будут созданы, когда и если они понадобятся. Может быть несколько веб-запросов, которые должны выполнять одни и те же запросы или обновления. Затем будет создан класс ProductService для предотвращения дублирования кода.
Таким образом, TDD управляет кодом, который будет написан. Проектирование происходит, когда вы делаете выбор реализации, а затем реорганизуете код в классы, чтобы устранить дублирование и контролировать зависимости. Когда вы добавляете код, вам нужно будет создавать новые классы, чтобы код оставался твердым. Но вам не нужно заранее решать, что вам понадобится класс Product и класс ProductService. Вы можете обнаружить, что жизнь просто прекрасна только с классом Product.
источник
ProductService
тогда нет . Но как TDD сказал вам, что вам нужна база данных и ORM?Другие могут не согласиться, но для меня многие из более новых методологий полагаются на предположение, что разработчик будет делать большую часть того, что более старые методологии прописывали просто по привычке или из личной гордости, что разработчик обычно делает что-то довольно очевидное для них, и работа заключена в чистый язык или более чистые части немного грязного языка, так что вы можете делать все тестовые дела.
Несколько примеров, когда я сталкивался с этим в прошлом:
Возьмите кучу подрядчиков, специализирующихся на технических работах, и скажите, что их команда - Agile и Test First. У них часто нет привычки, кроме как работать над спецификацией, и они не беспокоятся о качестве работы, пока она длится достаточно долго, чтобы завершить проект.
Попробуйте сначала сделать что-то новое, потратьте много времени на копирование тестов, так как вы обнаружите, что различные подходы и интерфейсы бесполезны.
Кодируйте что-то низкоуровневое и либо получите пощечину из-за недостатка охвата, либо напишите множество тестов, которые не имеют большого значения, потому что вы не можете высмеивать базовые поведения, к которым вы привязаны.
Если вы работаете с TDD, и это работает для вас, хорошо для вас, но есть много вещей (целые задания или этапы проекта), где это просто не добавляет ценности.
Ваш пример звучит так, как будто вы еще не работали над дизайном, так что либо вам нужно поговорить об архитектуре, либо вы создаете прототипы. Вы должны пройти через это сначала, по моему мнению.
источник
Я убежден, что TDD является очень ценным подходом к детальному проектированию системы - то есть API и объектной модели. Тем не менее, чтобы перейти к тому моменту, когда вы начинаете использовать TDD, вам нужно иметь общую картину дизайна, уже смоделированную каким-то образом, и вам необходимо иметь общую картину архитектуры, уже смоделированной каким-то образом. @ user414076 перефразирует Роберта Мартина как имеющего в виду идею дизайна, но не состоящую в браке с ней. Именно так. Вывод - TDD - не единственное мероприятие по проектированию, это то, как детали проекта раскрываются. TDD должен предшествовать другие действия по проектированию и вписываться в общий подход (такой как Agile), который учитывает, как создается и развивается общий дизайн.
К вашему сведению - две книги, которые я рекомендую по теме, которые дают реальные и реалистичные примеры:
Растущее объектно-ориентированное программное обеспечение, руководствуясь тестами - объясняет и дает полный пример проекта. Это книга о дизайне, а не о тестировании . Тестирование используется как средство определения ожидаемого поведения в процессе проектирования.
Разработка через тестирование Практическое руководство - медленный и пошаговый шаг по разработке полного, хотя и небольшого, приложения.
источник
TTD управляет обнаружением проекта путем неудачного теста, а не успеха, поэтому вы можете тестировать неизвестные и повторять повторные тесты, поскольку неизвестные в конечном итоге приводят к полному использованию модульных тестов - очень хорошая вещь для постоянного обслуживания и очень трудная вещь для попытки модернизация после написания / выпуска кода.
Например, требование может заключаться в том, что ввод может быть в нескольких различных форматах, еще не все известны. Используя TDD, вы сначала должны написать тест, который проверяет, что соответствующий вывод предоставляется при любом формате ввода. Очевидно, что этот тест не пройден, поэтому вы пишете код для обработки известных форматов и повторного тестирования. Поскольку неизвестные форматы открываются при сборе требований, новые тесты пишутся до того, как будет написан код, они также должны давать сбой. Затем пишется новый код для поддержки новых форматов, и все тесты перезапускаются, что снижает вероятность регрессии.
Также полезно думать о сбое модуля как о «незавершенном» коде, а не как «сломанный» код. TDD допускает незавершенные узлы (ожидаемые сбои), но уменьшает вероятность появления неисправных юнитов (неожиданные сбои).
источник
В вопросе указано:
Они пришли к такому выводу, подумав о том, как они собираются протестировать этот продукт. "Какой продукт это делает?" «Ну, мы могли бы создать сервис». «Хорошо, давайте напишем тест для такой услуги»
источник
Функциональность может иметь разный дизайн, и TDD не скажет полностью, какой из них лучший. Даже если тесты помогут вам создать более модульный код, это также может привести к созданию модулей, которые соответствуют требованиям тестов, а не производственной реальности. Таким образом, вы должны понимать, куда вы идете и как все должно вписаться в общую картину. Иначе говоря, существуют функциональные и нефункциональные требования, не забывайте последнее.
Что касается дизайна, я имею в виду книги Роберта К. Мартина (Agile Development), а также «Шаблоны архитектуры корпоративных приложений и дизайн драйверов доменов» Мартина Фаулера. Последнее особенно систематично в извлечении сущностей и отношений из требований.
Затем, когда вы получите хорошее представление о возможностях управления этими объектами, вы сможете использовать подход TDD.
источник
Нет.
Как вы можете проверить то, что вы не спроектировали в первую очередь?
Это не требования, это определения данных. Я не знаю, чем занимается ваше программное обеспечение, но вряд ли аналитики так говорят.
Вы должны знать, каковы инварианты вашей системы.
Требование будет что-то вроде:
Так что, если это единственное требование, у вас может быть такой класс:
Затем, используя TDD, вы должны написать тестовый пример перед реализацией метода order ().
Таким образом, второй тест не пройден, тогда вы можете реализовать метод order () так, как вам нравится.
источник
Вы совершенно правильно TDD приведете к хорошей реализации данного дизайна. Это не поможет вашему процессу проектирования.
источник
TDD очень помогает, но есть важная часть в разработке программного обеспечения. Разработчик должен слушать код , который пишется. Рефакторинг - третья часть в цикле TDD. Это основной шаг, на котором разработчик должен сосредоточиться и подумать, прежде чем перейти к следующему красному тесту. Есть ли дублирование? Применяются ли ТВЕРДЫЕ принципы? Как насчет высокой когезии и низкого сцепления? А как насчет имен? Присмотритесь к коду, который появляется из тестов, и посмотрите, есть ли что-то, что нужно изменить, переработать. Вопрос: код и код расскажут вам, как он будет разработан. Я обычно пишу наборы из нескольких тестов, изучаю этот список и создаю первый простой дизайн, он не должен быть «окончательным», обычно это не так, потому что он изменяется при добавлении новых тестов. Вот где приходит дизайн.
источник