Примечание автора: это перевод статьи Боба Мартина.
Меня вдохновило написать эту статью статья Марка Симана «Ловушка IsNullOrWhiteSpace» (@ploeh).
Статья Марка лаконична и хорошо изложена.
Пожалуйста, сначала прочтите его, прежде чем продолжать читать это.
Ловушка, о которой говорит Марк, — это частный случай более общей ловушки, которую я называю кража золота .
Я могу продемонстрировать эту ловушку, вернувшись к статье Марка.
Обратите внимание, что первый тест, который написал Марк, выглядел так:
Он уже попал в ловушку.[InlineData("Seven Lions Polarized" , "LIONS POLARIZED SEVEN" )] [InlineData("seven lions polarized" , "LIONS POLARIZED SEVEN" )] [InlineData("Polarized seven lions" , "LIONS POLARIZED SEVEN" )] [InlineData("Au5 Crystal Mathematics", "AU5 CRYSTAL MATHEMATICS")] [InlineData("crystal mathematics au5", "AU5 CRYSTAL MATHEMATICS")]
Почему? Потому что он уже украл золото .
Золото и шипы
Основная функциональность, которую пытается описать Марк, — это упорядочивание слов в алфавитном порядке.Естественно, его тесты отражают эту функциональность.
Основной функционал - золото и он украл его.
Проблема в том, что золото защищен невидимой колючей изгородью, которая опутает любого ничего не подозревающего программиста, который, будучи ослеплен золото , попытаюсь украсть его.
Что это за колючая изгородь? В случае Марка это значение null и пустая строка в качестве входных данных.
Я следую дисциплине TDD уже пятнадцать лет. Я узнал много нового об этой невидимой колючей изгороди.
Я усвоил урок, что она всегда рядом.
Я понял, что если ты попытаешься украсть золото слишком скоро невидимая изгородь станет мешать вашему прогрессу и разорвет ваши усилия на куски [1].
Итак, стратегия, которой я научился следовать, заключается в том, чтобы отвести взгляд от золота, пока я исследую изгородь и расчищаю от нее путь.
Разведка и очистка
Прежде чем перейти к основной функциональности, я пишу как можно больше тестов, которые игнорируют основную функциональность и вместо этого сосредотачиваются на исключительном, вырожденном вспомогательном поведении.Именно в такой последовательности.
Один за другим я пишу такие тесты и заставляю их проходить.
Поведение исключений
Это поведение, которое обнаруживает недопустимый ввод, с которым основная функциональность никогда не должна сталкиваться.Эти варианты поведения возвращают коды ошибок, регистрируют ошибки и/или выдают исключения.
В случае Марка обработка значений NULL — единственное исключительное поведение.
Но в более сложных приложениях обнаружение исключений может быть гораздо сложнее.
Конечно, эти случаи связаны с обработкой входных данных.
Но они также включают семантические нарушения, такие как удаление несуществующей записи или добавление уже существующей записи.
Дегенеративное поведение
Здесь мы говорим о входных данных, из-за которых основная функциональность «ничего не делает».Я взял слово «ничего» в кавычки, потому что иногда «ничего» может оказаться относительно трудным.
В случае Марка пустые строки и строки, состоящие из пробелов, являются дегенеративными входными данными.
В конце концов он решил проблему таких строк с помощью сложного набора условий и операций, которые возвращали пустую строку в случае одного пробельного символа или пустую строку в качестве входных данных, в противном случае все пробельные символы были удалены [2].
В общем, дегенеративные условия — это такие вещи, как пробелы, пустые строки, пустые коллекции, массивы нулевой длины и т. д. В более сложных приложениях дегенеративный случай может быть довольно сложным и требовать сложной обработки.
Рассмотрим, например, компилятор Java, который обрабатывает исходные файлы, содержащие тысячи строк, состоящих из точек с запятой и комментариев.
Каким должен быть результат обработки?
Вспомогательное поведение
Иногда эти случаи труднее всего обнаружить.Вспомогательное поведение — это поведение, которое окружает и поддерживает основную функциональность, но не является ее частью.
Например, функция getSize() класса Stack. Ответ на запрос размера не связан с основной функциональностью, реализующей LIFO. Дело в том, что вспомогательное поведение часто полезно для основного функционала по очевидным причинам.
Например, оказывается, что размер стека — это индекс массива, который используется для операций push и pop в стеках фиксированного размера.
Обычно я обнаруживаю, что после реализации всех вспомогательных функций реализовать основную функциональность становится гораздо проще.
Сначала я пишу все эти тесты и заставляю их проходить.
Я избегаю любых тестов, близких к основной функциональности, пока наконец не решу проблему прохождением тестов, охватывающих все, кроме основной функциональности.
Тогда и только тогда я возьму золото .
[1] Действительно, буквально позавчера я провел четыре часа, запутываясь в шипах, которые промахнулся и не расчистил должным образом.
В конце концов, git Reset - Hard оказался моим единственным вариантом.
[2] Охватывает ли он все возможные условия? А как насчет табуляции, новой строки, пробелов и непечатаемых символов? Теги: #tdd #.
NET #дизайн и рефакторинг #tdd
-
01 Ссылки Для Ux-Специалистов
19 Oct, 24 -
Карта Безопасности Ядра Linux
19 Oct, 24 -
Пользуетесь Ли Вы Sms-Рассылками?
19 Oct, 24