Технологии тестирования программ
Дав рабочее определение тестированию, необходимо ответить на вопрос – возможно ли обнаружить все ошибки программы. Оказывается, что ответ будет отрицательным даже для самых тривиальных программ. В общем случае невозможно обнаружить все ошибки программы. А это в свою очередь порождает экономические проблемы, задачи, связанные с функциями человека в процессе отладки, способы построения тестов.
Тестирование программы как черного ящика
Одним из способов изучения поставленного вопроса является исследование стратегии тестирования, называемой стратегией черного ящика, тестированием с управлением по данным, или тестированием с управлением по входу-выходу. При использовании этой стратегии программа рассматривается как черный ящик. Иными словами, такое тестирование имеет целью выяснение обстоятельств, в которых поведение программы не соответствует ее спецификации. Тестовые же данные используются только в соответствии со спецификацией программы (т.е. без учета знаний о ее внутренней структуре).
При таком подходе обнаружение всех ошибок в программе может быть достигнуто, если в качестве тестовых наборов использовать все возможные наборы входных данных. Следовательно, мы приходим к выводу, что для исчерпывающею тестирования программы требуется бесконечное число тестов.
Поскольку исчерпывающее тестирование исключается, нашей целью должна стать максимизация результативности капиталовложений в тестирование (иными словами, максимизация числа ошибок, обнаруживаемых одним тестом). Для этого мы можем рассматривать внутреннюю структуру программы и делать некоторые разумные, но, конечно, не обладающие полной гарантией достоверности предположения (например, разумно предположить, что если программа сравнивает два числа a и b, и в процессе тестирования она сочла равными a, принявшее значение 3, и b, принявшее значение 3, то она также сочтет равными a, принявшее значение 5, и b, принявшее значение 5).
Тестирование программы как белого ящика
Стратегия белого ящика, или стратегия тестирования, управляемого логикой программы, позволяет исследовать внутреннюю структуру программы. В этом случае специалист, проводящий тестирование, получает тестовые данные путем анализа логики программы (к сожалению, здесь часто не используется спецификация программы).
Сравним способ построения тестов при данной стратегии с исчерпывающим входным тестированием стратегии черного ящика. Непосвященному может показаться, что достаточно построить такой набор тестов, в котором каждый оператор исполняется хотя бы один раз; нетрудно показать, что это неверно. Не вдаваясь в детали, укажем лишь, что исчерпывающему входному тестированию может быть поставлено в соответствие исчерпывающее тестирование маршрутов. Подразумевается, что программа проверена полностью, если с помощью тестов удается осуществить выполнение этой программы по всем возможным маршрутам ее потока (графа) передач управления.
Последнее утверждение имеет два слабых пункта. Один из них состоит в том, что число не повторяющих друг друга маршрутов в программе – астрономическое. Чтобы убедиться в этом, рассмотрим представленный на рис. 3.4 граф передач управления простейшей программы. Каждая вершина, или кружок, обозначает участок программы, содержащий последовательность линейных операторов, которая может заканчиваться оператором ветвления. Дуги, оканчивающиеся стрелками, соответствуют передачам управления. По-видимому, граф описывает программу из 10–20 операторов, включая цикл DO, который исполняется не менее 20 раз. Внутри цикла имеется несколько операторов IF. Для того чтобы определить число неповторяющихся маршрутов при исполнении программы, подсчитаем число неповторяющихся маршрутов из точки А в В в предположении, что все входные данные взаимно независимы. Это число вычисляется как сумма 520 + 519 +... + 51 = 1014, или 100 триллионам, поскольку в данном случае число путей внутри цикла равно 5. Большинству читателей трудно оценить это число, поэтому приведем такой пример: если допустить, что на составление каждого теста мы тратим пять минут, то для построения набора тестов нам потребуется примерно один миллиард лет.
Конечно, в реальных программах условные переходы не могут быть взаимно независимы, т.е. число маршрутов исполнения будет несколько меньше. С другой стороны, реальные программы значительно больше, чем простая программа, представленная на рис. 3.4. Следовательно, исчерпывающее тестирование маршрутов, как и исчерпывающее входное тестирование, не только невыполнимо, но и невозможно.
Второй слабый пункт утверждения заключается в том, что, хотя исчерпывающее тестирование маршрутов является полным тестом и хотя каждый маршрут программы может быть проверен, сама программа будет содержать ошибки. Это объясняется следующим образом. Во-первых, исчерпывающее тестирование маршрутов не может дать гарантии того, что программа соответствует описанию. Например, вместо требуемой программы сортировки по возрастанию случайно была написана программа сортировки по убыванию. В этом случае ценность тестирования маршрутов невелика, поскольку после тестирования в программе окажется одна ошибка, т.е. программа неверна.
Во-вторых, программа может быть неверной в силу того, что пропущены некоторые маршруты. Исчерпывающее тестирование маршрутов не обнаружит их отсутствия. В-третьих, исчерпывающее тестирование маршрутов не может обнаружить ошибок, появление которых зависит от обрабатываемых данных. Существует множество примеров таких ошибок. Приведем один из них. Допустим, в программе необходимо выполнить сравнение двух чисел на сходимость, т.е. определить, является ли разность между двумя числами меньше предварительно определенного числа. Может быть написано выражение:
IF ((А –В) < EPSILON) ...
Безусловно, оно содержит ошибку, поскольку необходимо выполнить сравнение абсолютных величин. Однако обнаружение этой ошибки зависит от значений, использованных для А и В, и ошибка не обязательно будет обнаружена просто путем исполнения каждого маршрута программы.
Рис. 3.4. Граф передач управления небольшой программы
В заключение отметим, что, хотя исчерпывающее входное тестирование предпочтительнее исчерпывающего тестирования маршрутов, ни то, ни другое не могут стать полезными стратегиями, потому что оба они нереализуемы. Возможно, поэтому реальным путем, который позволит создать хорошую, но, конечно, не абсолютную стратегию, является сочетание тестирования программы как черного и как белого ящиков.