Вот правила Роберта С. Мартина для TDD :
- Вам не разрешается писать какой-либо производственный код, если только он не прошел неудачный модульный тест.
- Вам не разрешено писать больше модульных тестов, чем достаточно для провала; и ошибки компиляции - это ошибки.
- Вам не разрешено писать больше производственного кода, чем достаточно для прохождения одного неудачного модульного теста.
Когда я пишу тест, который кажется стоящим, но проходит без изменения производственного кода:
- Значит ли это, что я сделал что-то не так?
- Должен ли я избегать написания таких тестов в будущем, если это поможет?
- Должен ли я оставить этот тест там или удалить его?
Примечание: я пытался задать этот вопрос здесь: Могу ли я начать с прохождения модульного теста? Но я не мог сформулировать вопрос достаточно хорошо до сих пор.
testing
unit-testing
tdd
Даниэль Каплан
источник
источник
Ответы:
В нем говорится, что вы не можете написать производственный код, если только не пройдете неудачный модульный тест, а не то, что вы не можете написать тест, который проходит с самого начала. Цель правила - сказать: «Если вам нужно отредактировать производственный код, убедитесь, что вы сначала написали или изменили тест для него».
Иногда мы пишем тесты, чтобы доказать теорию. Тест проходит, и это опровергает нашу теорию. Затем мы не удаляем тест. Тем не менее, мы могли бы (зная, что у нас есть поддержка исходного кода) нарушить производственный код, чтобы убедиться, что мы понимаем, почему он прошел, когда мы этого не ожидали.
Если он окажется действительным и правильным тестом и не дублирует существующий тест, оставьте его там.
источник
Это означает, что либо:
Последняя ситуация встречается чаще, чем вы думаете. В качестве совершенно показательного и тривиального (но все же иллюстративного) примера предположим, что вы написали следующий модульный тест (псевдокод, потому что я ленивый):
Потому что все, что вам действительно нужно, это результат сложения 2 и 3.
Ваш метод реализации будет:
Но скажем, теперь мне нужно добавить 4 и 6 вместе:
Мне не нужно переписывать мой метод, потому что он уже охватывает второй случай.
Теперь предположим, что я обнаружил, что моей функции Add действительно нужно возвращать число с некоторым потолком, скажем, 100. Я могу написать новый метод, который проверяет это:
И этот тест сейчас провалится. Теперь я должен переписать свою функцию
чтобы это прошло.
Здравый смысл подсказывает, что если
проходит, вы не намеренно заставляете свой метод терпеть неудачу только для того, чтобы у вас был неудачный тест, чтобы вы могли написать новый код для того, чтобы пройти этот тест.
источник
add(2,3)
пройти, вы буквально вернули бы 5. Жестко закодировано. Затем вы бы написали тест, дляadd(4,6)
которого вы заставили бы вас написать производственный код, который проходит его, не прерываясьadd(2,3)
в то же время. Вы бы в конечном итоге сreturn x + y
, но вы бы не начать с ним. Теоретически. Естественно, Мартин (или, может быть, это был кто-то другой, я не помню) любит приводить такие примеры для образования, но не ожидает, что вы на самом деле будете писать такой тривиальный код таким образом.Ваш тестовый проход, но вы не ошиблись. Я думаю, это произошло потому, что производственный код не является TDD с самого начала.
Допустим, канонический (?) TDD. Нет никакого производственного кода, но есть несколько тестовых случаев (которые, конечно, всегда терпят неудачу). Мы добавляем производственный код для передачи. Тогда остановитесь здесь, чтобы добавить больше неудачных тестов. Снова добавьте производственный код для передачи.
Другими словами, ваш тест может быть своего рода функциональным тестом, а не простым модульным тестом TDD. Это всегда ценный актив для качества продукции.
Мне лично не нравятся такие тоталитарные, бесчеловечные правила; (
источник
На самом деле та же проблема возникла в додзё прошлой ночью.
Я сделал быстрое исследование этого. Вот что я придумал:
В принципе это не запрещено явным образом правилами TDD. Возможно, необходимы дополнительные тесты, чтобы доказать, что функция работает правильно для обобщенного ввода. В этом случае практика TDD оставлена на некоторое время в стороне. Обратите внимание, что отказ от практики TDD вскоре не обязательно нарушает правила TDD, если в это время не добавлен производственный код.
Дополнительные тесты могут быть написаны, если они не являются избыточными. Хорошей практикой будет тестирование разбиения классов эквивалентности. Это означает, что проверяются граничные случаи и по крайней мере один внутренний случай для каждого класса эквивалентности.
Однако при таком подходе может возникнуть одна проблема: если тесты проходят с самого начала, нельзя быть уверенным, что нет ложных срабатываний. Это означает, что могут быть тесты, которые пройдут, потому что тесты не реализованы правильно, а не потому, что рабочий код работает правильно. Чтобы предотвратить это, производственный код должен быть слегка изменен, чтобы прервать тест. Если это приводит к провалу теста, скорее всего, тест реализован правильно, и рабочий код можно изменить обратно, чтобы снова выполнить тест.
Если вы просто хотите практиковать строгий TDD, вы можете не писать никаких дополнительных тестов, которые проходят с самого начала. С другой стороны, в среде разработки предприятия на самом деле следует оставить практику TDD, если дополнительные тесты кажутся полезными.
источник
Тест, который проходит без изменения производственного кода, по своей сути не является плохим, и часто необходим для описания дополнительного требования или граничного случая. Пока ваш тест «кажется стоящим», как вы говорите, ваш, сохраните его.
Когда вы сталкиваетесь с проблемами, вы пишете уже проходящий тест в качестве замены для реального понимания проблемного пространства.
Мы можем представить себе две крайности: один программист, который пишет большое количество тестов «на всякий случай», другой ловит ошибку; и второй программист, который тщательно анализирует проблемное пространство, прежде чем писать минимальное количество тестов. Допустим, оба пытаются реализовать функцию абсолютного значения.
Первый программист пишет:
Второй программист пишет:
Первая реализация программиста может привести к:
Реализация второго программиста может привести к:
Все тесты пройдены, но первый программист не только написал несколько избыточных тестов (без необходимости замедляя их цикл разработки), но также не смог протестировать граничный случай (
abs(0)
).Если вы пишете тесты, которые проходят без изменения производственного кода, спросите себя, действительно ли ваши тесты приносят пользу или вам нужно больше времени уделять пониманию проблемного пространства.
источник
abs(n) = n*n
и прошел.abs(-2)
. Как и все, модерация является ключом.