дизайн середины приложения крупных размеров при выполнении TDD? [закрытый]

У меня есть хорошее схватывание поблочного тестирования, DI, насмешек, и все совершенство принципала дизайна, требуемое иметь как близко к полному покрытию кода как по-человечески возможный (единственный принципал ответственности, думают, 'как я протестирую это', поскольку я кодирую, и т.д....).

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

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

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

В противном случае как, черт возьми, Вы записали бы свой первый модульный тест на функцию высшего уровня в Вашей системе? Позволяет говорят, например - относительно веб-сервиса, где у Вас есть функция под названием DoSomethingComplicated (param1..., param6) представленный миру. Очевидно, запись теста сначала для простой функции как AddNumbers () тривиальна - но когда функция во главе стека вызовов, такого как это?

Вы все еще делаете дизайн заранее? Очевидно, Вы все еще хотите сделать дизайн 'архитектуры' - например, блок-схема, показывающая IE, говорящий с IIS, который говорит с сервисом окон через WCF, который говорит с Базой данных SQL... ERD, который показывает все Ваши таблицы SQL и их поля, и т.д...., но что относительно дизайна класса? Взаимодействия между классами, и т.д.? Вы разрабатываете это заранее или просто продолжаете писать тупиковый код, осуществляя рефакторинг взаимодействия, как Вы продвигаетесь, до всего этого соединяется и похож на него, будет работать?

Любой совет очень ценится

15
задан dferraro 31 December 2009 в 02:23
поделиться

4 ответа

Пишу ли я приложение целиком, используя только заглушенный код?

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

Лучше начать с наиболее важной функции и продвигаться оттуда, используя подход снаружи-внутрь . Часто это означает начинать с некоторого пользовательского интерфейса.

Я делаю это путем создания желаемого пользовательского интерфейса. Поскольку обычно мы не можем разрабатывать пользовательский интерфейс с помощью TDD, я просто создаю представление с помощью выбранной технологии. Никаких тестов там нет, но я подключаю пользовательский интерфейс к некоторому API (предпочтительно с использованием декларативной привязки данных), и тогда начинается тестирование.

Вначале я затем выполнял TDD свои модели ViewModels / Presentation и соответствующие контроллеры, возможно, жестко закодировав некоторые ответы, чтобы убедиться, что пользовательский интерфейс работает. Как только у меня появляется что-то, что не взрывается при запуске, я проверяю код (помните, многие небольшие дополнительные проверки).

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

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

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

Я все еще проектирую заранее?

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

Это более или менее ограничено

  • количеством и именами слоев (пользовательский интерфейс, логика представления, модель предметной области, доступ к данным и т. Д.).
  • Используемые технологии (WPF, ASP.NET MVC, SQL Server, .NET 3.5 или еще много чего)
  • Как мы структурируем производственный код и тестовый код, и какие технологии тестирования мы используем
  • Требования к качеству кода ( парное программирование, статический анализ кода, стандарты кодирования и т. д.)

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

12
ответ дан 1 December 2019 в 01:38
поделиться
  • Вы занимаетесь проектированием?

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

  • Пишете ли вы все приложение, используя только заглушенный код?

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

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

  • Как написать свой первый юнит-тест для функции высокого уровня?

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

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

  • Пожалуйста, не создавайте свой пользовательский интерфейс в первую очередь.

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

  • Пожалуйста, не проектируйте базу данных в первую очередь.

Базы данных - это подробности. Оставьте детали на потом. Скорее, проектируйте свою систему так, как будто вы понятия не имеете, какую БД вы используете, Храните любые понятия о схеме, таблицах, строках и столбцах вне ядра системы. Реализуйте свои бизнес правила так, как будто все данные постоянно хранятся в памяти. Затем добавьте базу данных позже, как только все бизнес-правила заработают. Опять-таки, я знаю, что это противоречит общепринятой мудрости, но подключение систем к базам данных слишком рано - это источник множества сильно искаженных конструкций

.
20
ответ дан 1 December 2019 в 01:38
поделиться
  • Вы пишете все приложение, используя только заглушенный код?

Для тестирования наших систем мы в основном выполняем тестирование модулей, интеграции и удаленных сервисов. В юнит-тестировании мы используем все длительные, трудоемкие и внешние сервисы, т.е. операции с базами данных, подключение к веб-сервисам или любое подключение к внешним сервисам. Это необходимо для того, чтобы наши тесты были быстрыми, независимыми и не зависели от реакции какой-либо внешней службы для обеспечения быстрой обратной связи. Этому мы научились нелегко, так как у нас есть несколько тестов, выполняющих операции с базой данных, что делает их действительно медленными, что противоречит принципу "Юнит-тесты должны быть быстрыми для запуска"

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

Однако, для тестирования любого типа удаленных служб , у нас есть тесты, которые подключаются к внешним службам, выполняют операции над ними и получают ответ. Для теста важен их ответ и конечное состояние, если это важно для теста. Важно то, что мы храним такие тесты в другом каталоге под названием remote (это соглашение, которое мы создали и которому следуем), и эти удаленные тесты выполняются нашим CI (continuous integration) сервером только тогда, когда мы сливаем любой код с основной/магистральной веткой и push/commit его в repo, так что мы быстро узнаем, были ли какие-то изменения в тех внешних сервисах, которые могут повлиять на наше приложение.

  • Я все еще занимаюсь проектированием заранее?

Да, но мы не занимаемся проектированием заранее, в основном, как сказал дядя Боб (Robert C. Martin). Кроме того, мы попадаем на белую доску перед тем, как погрузиться в кодирование, и создаем некоторые диаграммы сотрудничества классов только для того, чтобы прояснить и убедиться, что все в команде находятся на одной странице, и это также помогает нам разделить работу между членами команды.

1
ответ дан 1 December 2019 в 01:38
поделиться

+1 Хороший вопрос

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

TDD By Example не поможет, не думаю. IIRC проходит на простом примере. Я читаю книгу Роя Ошероува "Искусство юнит-тестирования" (The Art of Unit Testing), и хотя она, кажется, всесторонне охватывает такие инструменты и приемы, как насмешки и корешки, пока что пример тоже кажется довольно простым, и я не вижу, чтобы он подсказывал вам, как подойти к большому проекту.

1
ответ дан 1 December 2019 в 01:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: