Подтвердить что ты не робот

Как TDD делает рефакторинг проще?

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

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

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

Наконец, будет ли хорошая книга по TDD и/или рефакторингу адресовать такие проблемы? Если да, то что бы вы порекомендовали?

4b9b3361

Ответ 1

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

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

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

Обновление (на основе комментариев):

@Cybis поднял интересное возражение против моего утверждения о том, что рефакторинг не должен нарушать тесты, потому что рефакторинг не должен изменять поведение. Его возражение состоит в том, что рефакторинг изменяет API и поэтому проверяет "разрыв".

Во-первых, я призываю всех посетить каноническую ссылку на рефакторинг: Martin Fowler bliki. Только сейчас я просмотрел его, и на меня выскочила пара вещей:

  • Изменяет интерфейс рефакторинг? Мартин ссылается на рефакторинг как "изменение поведения", которое означает, что при изменении интерфейса /API то все вызывающие интерфейс /API также должен измениться. Включая тесты, я говорю.
  • Это не означает, что поведение изменилось. Опять же, Фаулер подчеркивает, что его определение рефакторинга заключается в том, что изменения - поведение сохранения.

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

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

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

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

Ответ 2

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

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

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

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

Я еще не прочитал его, но я слышал хорошие вещи о книге "XUnit Test Patterns - Рефакторинг тестового кода".

Ответ 3

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

Лично мне нравится TDD, но не поощряет over-TDD. То есть, не пишите слишком много случаев unit test. Единичных тестов должно быть достаточно. Если вы испытываете модульное тестирование, вы можете обнаружить, что у вас есть дилемма, когда вы хотите изменить архитектуру. Одно большое изменение в производственном коде будет приводить к большому количеству изменений unit test. Поэтому достаточно просто сохранить unit test.

Ответ 4

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

Затем вы пишете код для соответствия тесту.

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

Красная полоска, зеленая полоса, справа?

Рефакторинг Фаулера - это ссылка на рефакторинг, как ни странно.

Серия статей Скотта Амблера в статье доктора Добба ( "The Agile Edge" ) - это отличное прохождение TDD на практике.

Ответ 5

изменение алгоритма с более эффективным, например.

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

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

Ответ 7

Книга Кент Бек TDD.

Сначала проверьте. После принципов S.O.L.I.D ООП и использования хорошего инструмента рефакторинга необходимы, если это не требуется.

Ответ 8

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

Точка тестов и спецификаций - это определение правильного поведения системы. Итак, очень просто:

if definition of correctness changes
  change tests/specs
end

if definition of correctness does not change
  # no need to change tests/specs
  # though you still can for other reasons if you want/need
end

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