Как избежать создания плохих конструкций с TDD

17

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

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

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

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

изменить # 1:

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

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

RE «TDD не обязательно означает« тест-первый »: ( womp, btreat )

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

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

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

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

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

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

Объекты RE God:

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

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

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

Хорошо, я чувствовал, что было бы неплохо обновить некоторые мысли после рассмотрения проблемы на некоторое время.

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

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

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

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

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

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

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

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

    
задан Tom W 03.06.2011 в 18:36
источник
  • Я сейчас читаю: «Растущее объектно-ориентированное программное обеспечение, управляемое тестированием». Отлично читал по этому вопросу. –  Op De Cirkel 03.06.2011 в 20:33
  • У меня есть профессиональное тестирование с C #, которое некоторые комментарии предложили, это что-то вроде производной работы. Я выбрал его, потому что он был специфичен для C # и использует некоторые инструменты, на которые я смотрел раньше (NUnit, Ninject). –  Tom W 04.06.2011 в 12:00
  • Искусство Тестирования Ошерове неплохо, хотя это не относится к TDD-only. –  TrueWill 05.06.2011 в 03:30
  • Что касается ваших изменений: одним из основных принципов, которым вы должны следовать, является «ЯГНИ» - «Вам это не понадобится». Каждая строка кода, который вы пишете, должна способствовать дальнейшему развитию системы, как она существует прямо сейчас. Никогда не строите вещи, которые вам «понадобятся» позже, потому что шансов нет, и даже если вы это сделаете, вам может потребоваться изменить то, что, по вашему мнению, вам нужно, чтобы оно работало так, как вам сейчас нужно. Кодирование на интерфейсы - это хорошая практика «башни из слоновой кости», но извлечение интерфейса с помощью инструмента, такого как ReSharper, - это одноминутная операция, поэтому на самом деле сделайте это, когда вам это нужно. –  KeithS 09.11.2011 в 23:08

7 ответов

7

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

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

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

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

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

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

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

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

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

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

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

    
ответ дан KeithS 03.06.2011 в 20:04
  • Я пересматривал эту тему через некоторое время и перечитывал ответы, это наиболее соответствует тому, что я подумал о себе по этой теме. Я полагаю, это делает его «любимым» ответом, хотя, насколько это применимо в вопросе типа CW, для обсуждения. Я рассмотрел это более подробно как редактирование основного вопроса, если вам интересно. –  Tom W 09.11.2011 в 20:19
11

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

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

  

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

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

  

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

Снова: напишите один тест. Это требует полного понимания аспекта one функции one . Он требует этого, и он выражает это конкретно, в исполняемой форме.

    
ответ дан Carl Manaster 03.06.2011 в 19:00
6

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

  • TDD действительно поощряет неочевидные проекты. Часто это лучше, чем очевидные. Некоторые из ката, которые вы можете найти в Интернете, показывают эту функцию - там, где вы могли представить себе целый набор классов TDD, получается один или два с очень маленьким кодом. Я не согласен с тем, что он блокирует возможности разложения битов - мантра TDD - это красный, зеленый, рефакторинг. Я думаю, что секрет здесь - это не думать обо всех функциях сразу - придерживаться одного за раз с высокого уровня, прежде чем вы даже начнете думать о том, как это будет выполняться классами.
  • Это может быть так, но тогда, когда у вас есть ваша рефакторинговая шляпа, вы всегда можете реорганизовать свой большой класс на несколько классов, безопасно, зная, что ваши тесты подберут любые ошибки в вашем рефакторинге. TDD рекомендует рефакторинг в каждой возможности (всякий раз, когда у вас есть зеленый свет), поэтому объекты-боги не должны быть результатом.
  • Я не согласен с этим. Все TDD требует, чтобы вы знали одно, что вам нужно, и пишите этот тест. Тогда вы получите это, чтобы пройти. Тогда вы думаете о другом, что вам нужно. Различные катавы иллюстрируют это довольно хорошо. Эта книга посвящена оригинальной книге Кент Бекка о TDD.
  • Издеваться сложно, это правда. Кроме того, DSL для настройки тестовых данных - отличная идея:)
  • Насколько я знаю, по определению рефакторинг не требует больше тестов. Вы рефакторинг под зеленым баром - это означает, что вы никогда не пишете тесты для своего рефакторинга. Возможно, что рефакторинг приводит к созданию нового класса, в котором вам может понадобиться создать новый тестовый класс для тестирования вашего нового класса и одновременного тестирования тестов на новый тестовый класс, но, как правило, рефакторинг выполняется без добавление новых тестов.
ответ дан Peter Wiles 03.06.2011 в 19:08
  • Большой, большой +1, особенно для «TDD - длинная и извилистая дорога». @Tom - насколько хорошо вы были в дизайне класса после первой недели OOP? Это требует времени и практики, и всегда есть чему поучиться. –  TrueWill 03.06.2011 в 19:24
  • @TrueWill: Я не смотрю код, который я написал для моей университетской диссертации, если я даже могу его найти. Я взял книгу на C # одну неделю и начал работать дальше. Это была почти беспрепятственная катастрофа. –  Tom W 04.06.2011 в 11:52
2

Я думаю, вы попадаете под общее заблуждение, что 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
     

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

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. Это не единственный способ, и на самом деле я никогда не встречал никого, кто когда-либо практиковал «тест сначала» для каждого фрагмента кода, который они пишут.

    
ответ дан womp 03.06.2011 в 19:13
1

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

    
ответ дан btreat 03.06.2011 в 18:57
  • В моем опыте код, написанный на тестах, как правило, более сложен, что затрудняет запись тестов. Существует также риск того, что тесты никогда не будут записаны из-за временных сбоев. –  TrueWill 03.06.2011 в 19:19
  • Дисциплина для написания тестов должна быть там, пишите ли вы их до или после кода. В целом, однако, нужно идти с лучшей методологией, которая работает для них, будь то тест-тест или тест-тест. –  btreat 03.06.2011 в 19:34
1

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

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

Пример:

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

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

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

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

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

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

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

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

    
ответ дан Michael Venable 03.06.2011 в 19:15
1

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

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

ответ дан Gishu 04.06.2011 в 06:58