Это может быть довольно глупый вопрос, так как я нахожусь на моих первых попытках TDD. Мне нравилось чувство уверенности, которое оно приносит, и вообще лучшая структура моего кода, но когда я начал применять его на чем-то большем, чем одноклассные игрушечные примеры, я столкнулся с трудностями.
Предположим, вы пишете какую-то библиотеку. Вы знаете, что он должен делать, вы знаете общий способ его реализации (с точки зрения архитектуры), но вы продолжаете «открывать», что вам нужно вносить изменения в ваш публичный API во время написания кода. Возможно, вам нужно трансформировать этот закрытый метод в шаблон стратегии (и теперь вам нужно пропустить поддельную стратегию в ваших тестах), возможно, вы не туда-сюда возложили ответственность и разделили существующий класс.
Когда вы улучшаете существующий код, TDD кажется действительно подходящим вариантом, но когда вы пишете все с нуля, API, для которого вы пишете тесты, выглядит немного «размытым», если вы не делаете большой дизайн заранее. Что вы делаете, когда у вас уже есть 30 тестов для метода, чья сигнатура (и для этой части, поведение) изменилась? Это много тестов, которые нужно изменить, как только они сложатся.
Ответы:
То, что вы называете «большим дизайном сразу», я называю «разумным планированием архитектуры вашего класса».
Вы не можете вырастить архитектуру из юнит-тестов. Даже дядя Боб говорит это.
http://s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf , стр. 4
Я думаю, что было бы более разумно подходить к TDD с точки зрения проверки вашего структурного проекта. Откуда вы знаете, что дизайн неправильный, если вы его не тестировали? И как вы проверяете, что ваши изменения верны, не изменяя также исходные тесты?
Программное обеспечение «мягкое» именно потому, что оно может быть изменено. Если вас не устраивает количество изменений, продолжайте набираться опыта в архитектурном проектировании, и количество изменений, которые вам нужно будет внести в архитектуру вашего приложения, со временем уменьшится.
источник
Если вы делаете TDD. Вы не можете изменить сигнатуру и поведение, не пройдя тесты. Таким образом, 30 неудачных тестов были либо удалены в процессе, либо изменены / реорганизованы вместе с кодом. Или они теперь устарели, безопасны для удаления.
Вы не можете игнорировать 30 раз красный в вашем цикле красный-зеленый-рефактор?
Ваши тесты должны быть реорганизованы вместе с вашим рабочим кодом. Если вы можете себе позволить, перезапустите все тесты после каждого изменения.
Не бойтесь удалять тесты TDD. Некоторые тесты заканчивают тестированием строительных блоков, чтобы достичь желаемого результата. Желаемый результат на функциональном уровне - вот что имеет значение. Тесты на промежуточных этапах алгоритма, который вы выбрали / изобрели, могут иметь или не иметь большого значения, когда есть более одного способа достичь результата или вы изначально попали в тупик.
Иногда вы можете создать несколько достойных интеграционных тестов, сохранить их и удалить остальные. Это в какой-то степени зависит от того, работаете ли вы наизнанку или сверху вниз, и насколько большими шагами вы занимаетесь.
источник
Как только что сказал Роберт Харви, вы, вероятно, пытаетесь использовать TDD для чего-то, что должно обрабатываться другим концептуальным инструментом (то есть: «дизайн» или «моделирование»).
Попытайтесь спроектировать (или «смоделировать») свою систему достаточно абстрактным («общим», «расплывчатым») способом. Например, если вам нужно смоделировать автомобиль, просто используйте класс автомобиля с некоторыми неопределенными методами и полями, такими как startEngine () и int seat. То есть: опишите, что вы хотите представить публике , а не то, как вы хотите это реализовать. Попытайтесь раскрыть только основные функции (чтение, запись, запуск, остановка и т. Д.) И оставьте детальный код клиента на нем (prepareMyScene (), killTheEnemy () и т. Д.).
Запишите свои тесты, предполагая, что этот простой общедоступный интерфейс.
Измените внутреннее поведение ваших классов и методов, когда вам это нужно.
Если и когда вам понадобится изменить ваш публичный интерфейс и набор тестов, остановитесь и подумайте. Скорее всего, это признак того, что что-то не так в вашем API и в вашем дизайне / моделировании.
Нет ничего необычного в том, чтобы изменить API. Большинство систем в их версии 1.0 явно предупреждают программистов / пользователей о возможных изменениях в их API. Несмотря на это, непрерывный неконтролируемый поток изменений API является явным признаком плохого (или полностью отсутствующего) дизайна.
Кстати, у вас обычно должно быть несколько тестов для каждого метода. Метод, по определению, должен реализовывать четко определенное «действие» с какими-либо данными. В идеальном мире это должно быть одно действие, соответствующее одному тесту. В реальном мире нет ничего необычного (и не ошибочного) иметь несколько разных «версий» одного и того же действия и несколько разных соответствующих тестов. Конечно, вы должны избегать проведения 30 тестов по одному и тому же методу. Это явный признак того, что метод пытается сделать слишком много (и его внутренний код вышел из-под контроля).
источник
Я смотрю на это с точки зрения пользователя. Например, если ваши API-интерфейсы позволяют мне создавать объект Person с именем и возрастом, лучше использовать конструктор Person (строковое имя, int age) и методы доступа для имени и возраста. Создать новые тестовые примеры для новых людей с именем и возрастом просто.
Дуг
источник