Сколько должно быть тестов?
Насколько емкой должна быть обратная связь? Рассмотрим простую задачу: дано три целых числа, обозначающих длины сторон треугольника. Метод должен возвращать:
• 1 – в случае, если треугольник равносторонний;
• 2 – в случае, если треугольник равнобедренный;
• 3 – в случае, если треугольник не равносторонний и не равнобедренный.
Если длины сторон заданы некорректно (невозможно построить треугольник со сторонами заданной длины), метод должен генерировать исключение.
Вперед! Попробуйте решить задачу (мое решение, написанное на языке Smalltalk, приведено в конце данного подраздела).
Это отчасти напоминает игру «Угадай мелодию» («Я могу закодировать задачу за четыре теста!» – «А я – за три!» – «О’кей попробуйте».) Для решения задачи я написал шесть тестов, а Боб Биндер в своей книге Testing Object-Oriented Systems [29] («Тестирование объектно-ориентированных систем») для этой же самой задачи написал 65 тестов. Сколько на самом деле нужно тестов? Вы должны решить это сами, исходя из собственного опыта и рассуждений.
Когда я думаю о необходимом количестве тестов, я пытаюсь оценить приемлемое среднее время между сбоями (MTBF, Mean Time Between Failures). Например, в языке Smalltalk целые числа ведут себя как целые числа, а не как 32-битные значения. Иными словами, максимально возможное значение целого числа ограничивается не тридцатью двумя битами, а объемом памяти. Это означает, что вы можете обойтись без тестирования MAXINT. Безусловно, определенный предел существует, ведь теоретически можно создать целое число, для хранения которого не хватит имеющейся памяти. Но должен ли я тратить время на написание и реализацию теста, пытающегося заполнить память невероятно огромным целым числом? Как это повлияет на MTBF моей программы? Если я в обозримом будущем не собираюсь иметь дело с треугольниками, размер сторон которых измеряется такими числами, значит, моя программа не станет существенно менее надежной, если я не реализую такой тест.
Имеет ли смысл писать тот или иной тест? Это зависит от того, насколько аккуратно вы оцените MTBF. Если обстоятельства требуют, чтобы вы увеличили MTBF от 10 лет до 100 лет, значит, имеет смысл уделить время для разработки самых маловероятных и чрезвычайно редко возникающих ситуаций (если, конечно, вы не можете каким-либо иным образом доказать, что подобные ситуации никогда не могут возникнуть).
Взгляд на тестирование в рамках TDD прагматичен. В TDD тесты являются средством достижения цели. Целью является код, в корректности которого мы в достаточной степени уверены. Если знание особенностей реализации без какого-либо теста дает нам уверенность в том, что код работает правильно, мы не будем писать тест. Тестирование черного ящика (когда мы намеренно игнорируем реализацию) обладает рядом преимуществ. Если мы игнорируем код, мы наблюдаем другую систему ценностей: тесты сами по себе представляют для нас ценность. В некоторых ситуациях это вполне оправданный подход, однако он отличается от TDD.
TriangleTest
testEquilateral
self assert: (self evaluate: 2 side: 2 side: 2) = 1
testIsosceles
self assert: (self evaluate: 1 side: 2 side: 2) = 2
testScalene
self assert: (self evaluate: 2 side: 3 side: 4) = 3
testIrrational
[self evaluate: 1 side: 2 side: 3]
on: Exception
do: [: ex | ^self].
self fail
testNegative
[self evaluate: -1 side: 2 side: 2]
on: Exception
do: [: ex | ^self].
self fail
testStrings
[self evaluate: ‘a’ side: ‘b’ side: ‘c’]
on: Exception
do: [: ex | ^self].
self fail
evaluate: aNumber1 side: aNumber2 side: aNumber3
| sides |
sides:= SortedCollection
with: aNumber1
with: aNumber2
with: aNumber3.
sides first <= 0 ifTrue: [self fail].
(sides at: 1) + (sides at: 2) <= (sides at: 3) ifTrue: [self fail].
^sides asSet size
Когда следует удалять тесты?
Чем больше тестов, тем лучше, однако если два теста являются избыточными по отношению друг к другу, должны ли вы сохранить оба этих теста в наборе? Это зависит от двух критериев.
• Первый критерий – это уверенность. Никогда не удаляйте тест, если в результате этого снизится ваша уверенность в поведении системы.
• Второй критерий – это коммуникация. Если у вас есть два теста, которые тестируют один и тот же участок кода, однако читателем эти тесты рассматриваются как два различных сценария, сохраните оба теста.
Отсюда следует, что, если у вас есть два теста, которые можно считать избыточными как в отношении уверенности, так и в отношении коммуникации, удалите наименее полезный из этих тестов.
Как язык программирования и среда разработки влияют на TDD?
Попробуйте использовать подход TDD в среде Smalltalk с браузером Refactoring Browser. Теперь попробуйте работать в среде C++ с редактором vi. Почувствуйте разницу.
Читать дальше
Конец ознакомительного отрывка
Купить книгу