Почему при выполнении TDD я должен делать «достаточно» ”Чтобы пройти тестирование?

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

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

14
задан ryeguy 20 August 2010 в 09:02
поделиться

12 ответов

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

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

11
ответ дан 24 October 2019 в 20:53
поделиться

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

1
ответ дан 24 October 2019 в 20:53
поделиться

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

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

0
ответ дан 24 October 2019 в 20:53
поделиться

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

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

1
ответ дан 24 October 2019 в 20:53
поделиться

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

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

Некоторые другие ответы предполагают, что это основано на ЯГНИ. Отчасти это правда.

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

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

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

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

2
ответ дан 24 October 2019 в 20:53
поделиться

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

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

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

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

1
ответ дан 24 October 2019 в 20:53
поделиться

Выше много хороших ответов - YAGNI - это первый ответ, который приходит на ум.

Еще одна важная вещь в рекомендации «просто пройти тест» заключается в том, что TDD на самом деле представляет собой трехэтапный процесс:

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

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

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

0
ответ дан 24 October 2019 в 20:53
поделиться

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

0
ответ дан 24 October 2019 в 20:53
поделиться

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

4
ответ дан 24 October 2019 в 20:53
поделиться

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

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

3
ответ дан 24 October 2019 в 20:53
поделиться

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

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

3
ответ дан 24 October 2019 в 20:53
поделиться

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

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

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

1
ответ дан 24 October 2019 в 20:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: