Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Элементы тестирования
Тестирование – это выполнение программы с целью установить наличие ошибок. Рассмотрим тестирование как составную часть отладки. Основная трудность тестирования связана с его целью – заставить программу сбиться, т.е. отнестись к ней деструктивно. Автору программы трудно относиться к ней критично, поскольку поиск недостатков в плодах своей работы противоречит человеческой психологии, однако для отладки это необходимо. Начнем с нескольких общих замечаний. § Думать о тестировании нужно еще при разработке программы. Разрабатывая тот или иной фрагмент программы, представляйте себе, как он будет тестироваться. Планируя тестирование, предполагайте, что. в программе есть ошибки. § Тестирование имеет этапы, аналогичные этапам программирования: постановка задачи, проектирование, написание и проверка тестов, выполнение программы на тестах, изучение результатов. § Создавая набор тестов, необходимо для каждого теста описать ожидаемые значения выходных данных или результатов их обработки. § Нужно проверять, делает ли программа то, для чего она предназначена, а также, не делает ли она того, чего не должна делать. § Если набор тестов велик, то сначала программа проверяется на более простых тестах, способных выявить более очевидные ошибки. § Ошибки имеют свойство скапливаться. Отсюда парадоксальный вывод – чем больше ошибок найдено в некоторой части программы, тем больше шансов, что там есть еще. Поэтому данную часть программы нужно проверить с усиленным вниманием. § Не предполагайте, что тест будет использован только один раз. § Не упрощайте программу, чтобы облегчить тестирование. § Получив результаты тестирования, внимательно их изучите. Каждое несоответствие полученных и ожидаемых выходных данных дает информацию об ошибках в программе, необходимую для ее отладки. Основным творческим этапом тестирования является создание набора тестов, которые формируются с помощью двух основных подходов. Один использует спецификацию программы, другой – ее логику. При тестировании черного ящика, или с управлением по данным, программа рассматривается, как черный ящик, о внутреннем устройстве которого ничего не известно. Этот подход предназначен для выяснения обстоятельств, в которых поведение программы не соответствует ее спецификации. Крайним случаем такого подхода является исчерпывающее входное тестирование – в качестве тестов используются все возможные экземпляры данных. Однако это практически невозможно, поэтому нужно искать наборы входных данных, которые ограничены разумными пределами, но достаточно представительны. Реальные способы тестирования с управлением по данным основаны на том, что множество входных данных можно разбить на классы эквивалентности так, что все экземпляры из некоторого класса эквивалентности дают одинаковые результаты. Например, при вычислении корней квадратного уравнения ах2+bх+с=0 по его действительным коэффициентам все тройки чисел (а, b, с), для которых b2-4ас< 0, должны давать один и тот же ответ. Поэтому вместо тестирования программы для всех таких троек можно проверить только одну. Таким образом, используется набор тестов, представляющих свои классы эквивалентности. Второй подход называется тестированием белого ящика, или управляемым логикой программы. Здесь анализируется логика программы, а спецификация во внимание не принимается. Этот подход предназначен для выявления путей вычисления, на которых программа дает сбой. Крайний случай такого подхода – исчерпывающее тестирование путей. Однако даже в простых программах число путей слишком велико, чтобы их можно было перебрать, а тем более, построить для них набор тестовых данных. В реальных способах, основанных на логике программы, используются различные условия, которым должны удовлетворять наборы тестов. Например, выполняется ли каждый оператор, проходится ли каждая ветвь в операторах ветвлений, выполняется ли тело каждого цикла минимальное, максимальное и какое-нибудь промежуточное число раз. Используются также комбинации этих условий. Итак, для тестирования важен отбор тестов, дающих максимальную отдачу с точки зрения выявления ошибок. Обычно, формируя тестовый набор для отладки программы, вначале используют подход черного ящика, а затем изучают программу и добавляют тесты, связанные с логикой программы. Как правило, приемлемой оказывается следующая последовательность формирования тестового набора. 1. Готовятся тесты для каждой ситуации и каждой возможности, описанной в спецификации. К ним добавляются тесты для границ областей допустимых значений входных данных, областей выходных данных, для всех недопустимых условий. 2. По тексту программы проверяется, все ли ветвления выполняются на подобранных тестах в каждом направлении. Если необходимо, добавляются соответствующие тесты. 3. По тексту программы исследуется, охватывают ли тесты достаточно много возможных путей. Например, для каждого цикла (с предусловием или с перечислением) должен быть тест, соответствующий пути без выполнения тела цикла, с однократным его повторением и максимальным числом повторений. При необходимости тесты добавляются. 4. Проверяется чувствительность программы к отдельным особым значениям входных данных; при необходимости тесты добавляются. Пример 1. Рассмотрим процедуру simpdivisors, печатающей разложение числа типа integer на простые сомножители. procedure simpdivisors(n: integer); {Печать разложения натурального n на простые делители} var divisor: integer; {очередной делитель} Begin if n < 0 then begin write(n, ' = -'); n: = -n end else write(n, ' = '); if n< = 1 then write(n); divisor: = 2; while n > 1 do Begin if n mod divisor = 0 then Begin write(divisor, ' '); n: = n div divisor End else divisor: = divisor+1 End End; Спецификация процедуры проста. Она должна печатать разложение числа типа integer в виде последовательности сомножителей, разделенных пробелами, причем количество появлений сомножителя равно его степени в разложении числа. Общий вид печати – " число = разложение", например, 13 = 13 или -10 = -2 5. Каждый тест – это одно целое число. Вначале согласно спецификации возьмем пограничные натуральные значения (в типе integer) -32 768 и 32 767. Поведение данной процедуры для недопустимых значений не описано, поэтому добавлять недопустимые значения в данном случае некорректно. Однако граничные значения могут быть как у входных, так и у выходных данных. Границу у выходных данных можно связать с длиной последовательности сомножителей. Разложение простых чисел состоит из одного сомножителя, поэтому добавим наименьшее и наибольшее (в типе integer) простые числа 2 и 32749. Самое длинное разложение получается у максимальной степени числа 2 в типе integer – отрицательного числа -32 768, но оно уже есть. Наконец, добавим какие-нибудь промежуточные значения, положительное и отрицательное, например 72 и -111. С помощью текста процедуры убедимся, что на данных тестах ветвления выполняются в каждом направлении, а тело цикла – один и много раз. Однако тело цикла не выполняется ни разу, если аргумент равен -1, 0 или 1. Из этих особых значений добавим 0 и -1. Таким образом, получился набор тестов, который записан вместе с ожидаемыми результатами в виде следующей таблицы.
Для тестирования процедуры напишем простую программу с вызовами simpdivisors и writeln для разделения результатов. Такого рода программы называются драйверами. По возможности в них следует включать сверку полученных и ожидаемых результатов, а не просто печать результатов. Это облегчает анализ результатов тестирования. program driver; procedure simpdivisors(n: integer); … End; Begin simpdivisors(-32768); writeln; simpdivisors(32767); writeln; … simpdivisors(0); writeln; End. Запустим программу и получим результаты. Все тесты окажутся пройденными, кроме первого. Результат для него будет иметь следующий вид. -32768 = - -32768 С учетом обработки остальных отрицательных чисел этот результат однозначно указывает, что -32 768 при выполнении n: =-n не превратилось в 32 768, которого попросту нет в типе integer. Ошибка связана с тем, что в процедуре не учтены особенности машинного представления целых чисел. В данной ситуации возможны два выхода. Можно изменить спецификацию, сузив область данных (от -32 767 до 32 767), однако лучше в процедуру добавить проверку параметра на равенство -32 768 и дополнительную обработку этого значения. Естественно, после этого нужно повторить тестирование и убедиться, что все в порядке.
|