Как избежать создания плохих дизайнов с помощью TDD - PullRequest
17 голосов
/ 03 июня 2011

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

До сих пор я обнаружил, что:

  • TDD для меня, кажется, способствует появлению бессвязных, неочевидных конструкций.Ограничение на то, что нельзя писать код без теста, имеет тенденцию блокировать возможности разделять функциональность на независимые блоки.Разрабатывать и писать тесты для такого количества функций одновременно на практике слишком сложно
  • TDD имеет тенденцию поощрять создание «Объектов Бога», которые делают все - потому что вы уже написали множество классов-насмешников для класса x,но мало для класса y, поэтому кажется логичным в то время, что класс x должен также реализовать функцию z вместо того, чтобы оставлять ее классу y.
  • Для написания тестов перед написанием кода требуется полное понимание каждогоЗапутанность проблемы, прежде чем ее решить.Это кажется противоречием.
  • Мне не удалось заставить команду начать использовать насмешливый фреймворк.Это означает, что существует множество раздува, созданного исключительно для проверки конкретной функции.Для каждого протестированного метода вам, как правило, понадобится подделка, единственная задача которой - сообщать, что тестируемый класс вызывает то, что должен.Я начинаю замечать, что пишу что-то, похожее на DSL, исключительно для создания экземпляров тестовых данных.
  • Несмотря на все вышеперечисленное, TDD создал рабочий проект с несколькими загадочными ошибками, в отличие от шаблона разработки, к которому я привык,Рефакторинг растущего беспорядка, который в результате, однако, потребовал, чтобы я временно отказался от TDD и просто сделал это.Я верю, что тесты будут продолжать обеспечивать корректность метода.Попытка TDD выполнить рефакторинговое упражнение, которое, как я чувствую, просто разрастется еще больше.

Тогда возникает вопрос: «Есть ли у кого-нибудь какие-либо советы, чтобы уменьшить влияние проблем, перечисленных выше?».Я не сомневаюсь, что насмешливые рамки были бы полезны;однако в настоящее время я уже испытываю удачу, пытаясь что-то, что, кажется, просто производит бессвязный код.

edit # 1:

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

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

RE«TDD не обязательно означает« сначала тест »»: ( womp, btreat )

«Золотое правило» в каждом тексте, который я нашел по этому вопросу, «Красный, Зеленый»Рефакторинг ".То есть:

  • Написать тест, который ДОЛЖЕН завершиться неудачей
  • Написать код, который пройдет тест
  • Измените код так, чтобы он прошел тест самым практичным образом.

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

RE DSL для тестовых данных: ( Michael Venable )

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

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

RE Объекты Бога:

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

(Модераторам: я добавил свои ответы на посты здесь, потому что поле комментария недостаточно длинное, чтобы содержать детали, которые я хотел бы.)

edit # 2 (примерно послепять месяцев):

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

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

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

Эта ситуация возникла, потому что я буквально воспринял правило «код для интерфейса»,но продолжал писать классы, которые пытались представить реальность.Довольно давно я впервые сделал заявление:

Классы не должны пытаться представлять реальность.Объектная модель должна пытаться решить только имеющуюся проблему.

... которую я повторял с тех пор, как смог;для себя и для всех, кто будет слушать.

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

Это не значит, что я считаю, что «код для интерфейса» - это чушь. Это означает, что кодирование интерфейса в первую очередь полезно, когда интерфейсы представляют реальные бизнес-функции, а не свойства некоторой воображаемой идеальной объектной модели, которая выглядит как миниатюрная копия реальной жизни, но не учитывает ее единственное значение в жизнь, чтобы ответить на вопрос, который вы изначально задали. Сила TDD в том, что он не может производить такие модели, кроме как случайно. Поскольку он начинается с постановки вопроса и заботится только о получении ответа, ваше эго и предшествующее знание системы не затрагиваются.

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

Ответы [ 7 ]

11 голосов
/ 03 июня 2011

TDD не дразнит. Иногда имитация облегчает разработку тестов, но если при первом прохождении в TDD вы начинаете с макетов, вы, вероятно, не получаете наилучшего возможного введения в практику.

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

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

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

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

Еще раз: напишите один тест. Это требует полного понимания аспекта one one . Он требует этого и конкретно выражает его в исполняемом виде.

7 голосов
/ 03 июня 2011

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

Более конкретно для каждой точки:

1: TDD поощряет дизайн, который делает не больше или меньше того, что должен, он же «ЯГНИ» (вам это не понадобится). Это "сделай это свет". Вы должны сбалансировать это с «делай все правильно», то есть для включения в систему правильных концепций и шаблонов SOLID. Я придерживаюсь следующего правила: при первом использовании строки кода сделайте так, чтобы она работала. На второй ссылке на эту строку сделайте его читабельным. На третьем сделайте это ТВЕРДЫМ. Если строка кода используется только еще одной строкой кода, в то время не имеет особого смысла вставлять полностью твердотельный дизайн, разбивая код на абстрагированный от интерфейса класс, который можно подключить и поменять местами. из. Тем не менее, вы должны иметь дисциплину, чтобы вернуться и рефакторинг кода, как только он начинает получать другие применения. Дизайн TDD и Agile - это ВСЕ о рефакторинге. Вот загвоздка; как и в случае с водопадом, он просто стоит дороже, потому что вам нужно вернуться к этапу проектирования, чтобы внести изменения.

2: Опять же, это дисциплина. Принцип единой ответственности: объект должен делать одну конкретную вещь и быть единственным объектом в системе, который делает эту вещь. TDD не позволяет вам быть ленивым; это просто поможет вам узнать, где вы можете быть ленивым. Кроме того, если вам нужно создать много частичных макетов класса или много полнофункциональных полноценных макетов, вы, вероятно, неправильно проектируете объекты и тесты; ваши объекты слишком велики, у вашего SUT слишком много зависимостей и / или область вашего теста слишком широка.

3: Нет, это не так. Это требует, чтобы вы думали о том, что вам нужно, когда вы пишете свой набор тестов. Вот где действительно блестят помощники рефакторинга, такие как ReSharper (для MSVS); Alt + Enter - это ваш ярлык «сделай это». Допустим, вы TDDing нового класса, который будет записывать файл отчета. Первое, что вы делаете, это создаете новый экземпляр этого класса. «Подожди», - жалуется РеШарпер. «Я не могу найти этот класс!». «Так что создавай», говоришь ты, нажимая Alt + Enter. И это так; теперь у вас есть пустое определение класса. Теперь вы пишете вызов метода в своем тесте. «Подождите, - восклицает ReSharper, - этот метод не существует!», И вы говорите «затем создайте его», нажав Alt + Enter. Вы только что запрограммировали тестирование; у вас есть скелетная структура для вашей новой логики.

Теперь вам нужен файл для записи. Вы начинаете с ввода имени файла в виде строкового литерала, зная, что когда RS жалуется, вы можете просто сказать ему добавить параметр в определение метода. Подождите, это не модульный тест. Это требует метода, который вы создаете, чтобы прикоснуться к файловой системе, а затем вам нужно вернуть файл и пройти его, чтобы убедиться, что он правильный. Итак, вы решили вместо этого пройти поток; это позволяет вам передавать в MemoryStream, который идеально совместим с юнит-тестами. Есть , где TDD влияет на проектные решения; в этом случае решение состоит в том, чтобы сделать класс более твердым заранее, чтобы его можно было проверить. Это же решение дает вам гибкость для передачи данных куда угодно в будущем; в память, файл, по сети, именованный канал, что угодно.

4: Гибкая команда программирует по соглашению. Если нет соглашения, это блок; если команда заблокирована, код не должен быть написан. Чтобы решить блок, руководитель группы или руководитель проекта принимает командное решение. Это решение правильно, пока не доказано неправильно; если это заканчивается неправильно, это должно быть сделано быстро, чтобы команда могла двигаться в новом направлении, не возвращаясь назад. В вашем конкретном случае попросите вашего менеджера принять решение - Rhino, Moq и т. Д. - и исполните его. Все это будет на тысячу процентов лучше, чем тесты, написанные от руки.

5: Это должна быть реальная сила TDD.У вас есть класс;его логика - беспорядок, но он верен, и вы можете доказать это, запустив тесты.Теперь вы начинаете рефакторинг этого класса, чтобы сделать его более твердым.Если рефакторинг не изменяет внешний интерфейс объектов, тогда тесты даже не должны меняться;вы просто очищаете некоторую логику метода, о которой не заботятся тесты, кроме того, что она работает.Если вы действительно меняете интерфейс, то вы меняете тесты, чтобы делать разные вызовы.Это требует дисциплины;очень просто прогнать тест, который больше не работает, потому что тестируемый метод не существует.Но вы должны убедиться, что весь код в вашем объекте все еще выполняется надлежащим образом.В этом может помочь инструмент покрытия кода, который может быть интегрирован в процесс сборки CI и «сломать сборку», если покрытие не подходит для работы.Однако обратная сторона покрытия на самом деле двойная: во-первых, тест, который добавляет покрытие ради покрытия, бесполезен;каждый тест должен доказать, что код работает должным образом в какой-то новой ситуацииКроме того, «охват» не является «упражнением»;ваши тестовые наборы могут выполнять каждую строку кода в SUT, но они не могут доказать, что строка логики работает в любой ситуации.

Все это говорит о том, что был очень мощный урок в том, что TDD будет и выигрыватьне дал мне, когда я впервые узнал об этом.Это было кодовое додзё;задача состояла в том, чтобы написать синтаксический анализатор римских цифр, который бы взял строку римских цифр и вернул целое число.Если вы понимаете правила римских цифр, это легко спроектировать заранее и может пройти любой заданный тест.Однако дисциплина TDD может очень легко создать класс, который содержит словарь всех значений, указанных в тестах, и их целых чисел.Это случилось в нашем додзё.Вот загвоздка;если действительные заявленные требования синтаксического анализатора заключались в том, что он обрабатывал только те числа, которые мы тестировали, мы не сделали ничего плохого;система «работает», и мы не тратили время на разработку чего-то более сложного, которое работает в общем случае.Однако мы, новые агилиты, посмотрели на болото и сказали, что такой подход глуп;мы «знали», что это должно быть умнее и надежнее.Но разве мы?Это сила и слабость TDD;вы можете создать не более или менее систему, которая соответствует заявленным требованиям пользователя, потому что вы не должны (и часто не можете) писать код, который не соответствует или не подтверждает некоторые требования системы, предоставленные вам лицом, оплачивающимbills.

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

Если в ваших тестах есть конфликт, это блок.Допустим, у вас есть тест, который подтверждает, что данный метод возвращает X с данными A, B и C. Теперь у вас есть новое требование, и при разработке тестов вы обнаруживаете, что теперь тот же самый метод должен выводить Y, когда заданы A, B иC. Ну, предыдущий тест является неотъемлемой частью доказательства того, что система работала по-старому, поэтому изменение этого теста для подтверждения того, что теперь он возвращает Y, может нарушить другие тесты, построенные на этом поведении.Чтобы решить эту проблему, необходимо уточнить, что либо новое требование является изменением поведения по сравнению со старым, либо одно из поведений было неправильно выведено из требований приемки.

6 голосов
/ 03 июня 2011

Я бы очень рекомендовал продолжить некоторое время на вашем подходе, а затем прочитать книгу Джерарда Мезароса "Тестовые шаблоны xUnit" и попытаться применить его рекомендации.TDD - это длинная и извилистая дорога, и для того, чтобы увидеть преимущества, требуется много времени.Мои краткие ответы на некоторые из ваших вопросов приведены ниже:

  • TDD действительно поощряет неочевидные конструкции.Часто они лучше, чем очевидные.Некоторые из катов, которые вы можете найти в Интернете, показывают эту функцию - где вы, возможно, представляли целый набор классов, результаты TDD одного или двух с очень небольшим кодом.Я не согласен, что это блокирует возможности выделять биты - мантра TDD - красный, зеленый, рефакторинг.Я думаю, что секрет здесь не в том, чтобы думать обо всех функциях одновременно - придерживайтесь одной за раз с высокого уровня, прежде чем вы даже начнете думать о том, как это будет достигнуто классами.
  • случае, но тогда, когда у вас есть шляпа рефакторинга, вы всегда можете реорганизовать свой большой класс в несколько классов, будучи уверенными в том, что ваши тесты обнаружат любые ошибки в вашем рефакторинге.TDD поощряет рефакторинг при каждой возможности (когда у вас есть зеленый свет), поэтому объекты бога не должны быть результатом.
  • Я не согласен с этим.Все, что требуется от TDD, - это знать, что вам нужно, и писать этот тест.Тогда вы получаете это пройти.Тогда вы думаете о другой вещи, которая вам нужна.Различные каты иллюстрируют это довольно хорошо.Оригинальная книга Кента Бека по TDD также иллюстрирует этот процесс.
  • Насмешка трудна, это правда.Также отличной идеей является DSL для настройки тестовых данных:)
  • Насколько я знаю, рефакторинг по определению не требует дополнительных тестов.Вы выполняете рефакторинг под зеленой полосой - это означает, что вы никогда не пишете тесты для своего рефакторинга.Возможно, что рефакторинг приведет к созданию нового класса, и в этот момент вы можете захотеть создать новый тестовый класс, чтобы протестировать ваш новый класс и переместить тесты по одному в новый тестовый класс, но обычно рефакторинг выполняется бездобавление новых тестов.
2 голосов
/ 03 июня 2011

Я думаю, что вы попадаете под распространенное заблуждение, что TDD всегда означает «сначала проверить». Разработка в тестовом режиме не обязательно совпадает с TDD. TDD - это методология разработки программного обеспечения, которая фокусируется на написании тестируемого кода. Не существует строгого требования всегда сначала писать тесты, чтобы практиковать TDD.

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

TDD for me seems to encourage rambling, non-obvious designs to take

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

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

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

TDD tends to encourage the creation of 'God Objects' that do

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

I haven't been able to get the team on-side to start using a mocking

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

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

Writing tests before you write code requires that you have a complete

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

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

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

1 голос
/ 04 июня 2011

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

Как только он пройдет, вам нужно "рефакторинг".Маленькое слово, но большое значение - это шаг «сделай или сломай».Вы улучшаете свой дизайн в несколько небольших шагов.Однако TDD не заменит опыт ... который вытекает из практики.Таким образом, опытный программист с / без TDD может все же закончить производство лучшего кода, чем новичок с TDD - потому что он / она знает, на что обращать внимание.Так как ты туда попал?Вы учитесь у людей, которые этим занимались.

  • Я бы порекомендовал сначала книгу Бека TDD By Example .(Книга Фримена и Прайса GOOS хороша, но вы получите больше пользы от нее, если будете некоторое время заниматься TDD.)
  • Для того, чтобы проникнуть в мысли Гуру, посмотрите Чистый код Боба Мартина.Это дает вам простую эвристику для оценки вашего выбора.Я в главе 3;Я даже настроил упражнение на групповое чтение @ работа.Как говорится в книге, чистый код - это мера дисциплины, техника + «код-смысл».
1 голос
/ 03 июня 2011

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

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

Пример:

  LoadModelSetupFromTestFileCollection("VariableSetToScript.xml");
  AssertVariable("variable").HasValue(3);

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

Лучшие предложения, которые я могу дать:

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

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

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

  • Тестовый код, который похож на DSL-подобный язык, имеет большое значение в обслуживании и облегчает создание новых тестов, IMO.

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

1 голос
/ 03 июня 2011

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

...