При выполнении TDD, почему я должен делать «достаточно», чтобы пройти тест? - PullRequest
14 голосов
/ 21 августа 2010

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

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

Ответы [ 12 ]

11 голосов
/ 21 августа 2010

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

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

4 голосов
/ 21 августа 2010

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

3 голосов
/ 21 августа 2010

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

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

3 голосов
/ 21 августа 2010

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

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

2 голосов
/ 21 августа 2010

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

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

Некоторые другие ответы предполагают, что это основано на YAGNI.Это отчасти верно.

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

Если вы напишите 10 тестов, чтобы охватить случаи, когда param1 равен нулю, param2 равен нулю, string1 пуста, int1 отрицателен,и текущий день недели - выходные, а затем приступить к реализации этого, вам придется сразу же совмещать много сложностей.Это открывает пространство для появления ошибок, и становится очень трудно разобраться, почему тесты не выполняются.

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

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

1 голос
/ 21 августа 2010

Причина этого принципа проста. Насколько практично придерживаться, это отдельный вопрос.

Причина в том, что если вы пишете больше кода, чем требуется для прохождения текущего теста, вы пишете код, который по определению не проверен. (Это не имеет ничего общего с YAGNI.)

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

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

1 голос
/ 21 августа 2010

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

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

1 голос
/ 21 августа 2010

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

1 голос
/ 21 августа 2010

Это отличный вопрос. Вам необходимо найти баланс между написанием всех тестов во вселенной возможных тестов и наиболее вероятными сценариями пользователя. Одного теста, IMHO, недостаточно, и я обычно хотел бы написать 3 или 4 теста, которые представляют наиболее распространенное использование этой функции. Мне также нравится писать тесты на лучший случай и тест наихудшего случая.

Написание многих тестов поможет вам предвидеть и понимать потенциальное использование вашей функции.

0 голосов
/ 22 августа 2010

Множество хороших ответов выше - YAGNI - первый ответ, который приходит на ум.

Другая важная вещь в отношении принципа «просто получить прохождение теста» заключается в том, что TDD на самом деле является трехэтапным процессом.:

Красный> Зеленый> Рефакторинг

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

Трудно войти в эту привычку, но придерживайтесь ее, так как это странно удовлетворительный способ работы, как только вы попадете вцикл.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...