2009-12-31 2 views
15

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

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

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

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

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

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

Любой совет высоко ценится

ответ

12

Я пишу всю заявку, используя только прошитый код?

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

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

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

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

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

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

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

Должен ли я по-прежнему проектировать переднюю панель?

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

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

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

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

+0

Спасибо за отличный и подробный ответ. Это звучит очень похоже на то, как я закодировал свое последнее приложение .. (за исключением того, что я «обманывал» при написании тестов сначала в большинстве мест). Возможно, переход от модульного тестирования к TDD действительно не меняет способ проектирования и архивирования, поскольку я подумал ... Поэтому я должен спросить - вы очень строги с выполнением тестов в первую очередь? Когда-либо находишь это просто, просто написать код перед тестом? Если да, то как часто это происходит? И в каких-либо конкретных шаблонах/ситуациях? – dferraro

+2

Я очень строг, когда дело доходит до теста - сначала, так как я нахожу, что * Красная * фаза Red/Green/Refactor очень важна - я часто писал тест, который сразу же стал зеленым, несмотря на противоположное намерение. Это означает, что тест не проверяет, что я думал, что он тестирует, поэтому его нужно переписать. Это происходит со мной ок. один раз в день, но эта защита недоступна, когда вы пишете тесты после этого. Очень редко я пишу без тестирования, но когда это происходит, я удаляю код спайка, когда я закончил, а затем TDD верную реализацию, основанную на моем опыте по шипу. –

1

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

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

TDD На пример не поможет, я не думаю. IIRC - это простой пример. Я читаю «The Art of Unit Testing» Роя Ошероу, и, хотя он, похоже, всесторонне охватывает инструменты и методы, такие как mocks и stub, пример пока выглядит довольно простым, и я не вижу, чтобы он рассказывал вам, как подойти к большому проекту.

19
  • У вас есть дизайн спереди?

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

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

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

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

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

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

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

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

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

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

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

+0

Удивительный ответ. Еще раз спасибо – dferraro

+1

«Пожалуйста, не создавайте свой интерфейс». Я категорически не согласен. Без (статического) интерфейса сначала вы можете просто кодировать неправильную вещь. Еще один хороший текст: http://www.codinghorror.com/blog/2008/04/ui-first-software-development.html –

+0

Еще один хороший ответ: http://stackoverflow.com/questions/1554419/wheni-i- приступить к разработке-а-программное обеспечение-UI-дизайн или-база-дизайн, который-должен –

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

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

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

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

  • Должен ли я до сих пор разрабатывать дизайн спереди?

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

Смежные вопросы