Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ТРПП пособие Шишов.doc
Скачиваний:
152
Добавлен:
17.11.2018
Размер:
3.25 Mб
Скачать

13.3. Методы тестирования

Окончательная проверка корректности программ (т. е. проверка соответствия их внешним спецификациям), проверка на отсутствие алгоритмических ошибок и ошибок в организации программы осуществляется тестированием. Программы проверяются на функционирование с различными исходными данными. Результаты функционирования программ сравниваются с эталонными значениями. Программу условно можно считать правильной, если её запуск для выбранной системы тестовых исходных данных во всех случаях дает правильные результаты.

При тестировании модулей программного обеспечения, так же, как при проектировании и кодировании возможно применение как восходящего, так и нисходящего подходов.

Различают два подхода к формированию тестов: структурный и функциональный. Каждый из указанных подходов имеет свои особенности и области применения.

Структурный подход базируется на том, что известка структура тестируемого программного обеспечения, в том числе его алгоритмы («стеклянный ящик»). В этом случае тесты строят так, чтобы проверить правильность реализации заданной логики в коде программы.

Структурное тестирование называют также тестированием по «маршрутам», так как в этом случае тестовые наборы формируют путем анализа маршрутов, предусмотренных алгоритмом. Под маршрутами при этом понимают последовательности операторов программы, которые выполняются при конкретном варианте исходных данных.

В основе структурного тестирования лежит концепция максимально полного тестирования всех маршрутов программы. Так, если алгоритм программы включает ветвление, то при одном наборе исходных данных может быть выполнена последовательность операторов, реализующая действия, которые предусматривает одна ветвь, а при втором – другая. Соответственно, для программы будут существовать маршруты, различающиеся выбранным при ветвлении вариантом.

Считают, что программа проверена полностью, если с помощью тестов удается осуществить выполнение программы по всем возможным маршрутам передач управления. Однако нетрудно видеть, что даже в программе среднего уровня сложности число неповторяющихся маршрутов может быть очень велико, и, следовательно, полное или исчерпывающее тестирование маршрутов, как правило, невозможно.

Функциональный подход основывается на том, что структура программного обеспечения не известна («черный ящик»). В этом случае тесты строят, опираясь на функциональные спецификации. Этот подход называют также подходом, управляемым данными, так как при его использовании тесты строят на базе различных способов декомпозиции множества данных.

Наборы тестов, полученные в соответствии с методами этих подходов, обычно объединяют, обеспечивая всестороннее тестирование программного обеспечения.

13.4. Требования и рекомендации по тестированию программ

Сформулируем рекомендации к организации тестирования, которые применимы и при структурном и при функциональном подходах к его проведению.

Вычислять эталонные результаты нужно обязательно   до,   а не   после получения машинных результатов. В противном случае имеется опасность невольной подгонки вычисляемых значений под желаемые, полученные ранее на машине

Тестовые данные должны обеспечить проверку всех возможных условий возникновения ошибок:

  • очередной тестовый прогон должен контролировать нечто такое, что еще не было проверено на предыдущих прогонах;

  • первый тест должен быть максимально прост, чтобы проверить, работает ли программа вообще;

  • арифметические операции в тестах должны предельно упрощаться для уменьшения объема вычислений;

  • количества элементов последовательностей, точность для итерационных вычислений, количество проходов цикла в тестовых примерах должны задаваться из соображений сокращения объема вычислений;

  • минимизация вычислений не должна снижать надежности контроля;

  • тестирование должно быть целенаправленным и систематизированным, так как случайный выбор исходных данных привел бы к трудностям в определении ручным способом ожидаемых результатов; кроме того, при случайном выборе тестовых данных могут оказаться непроверенными многие ситуации;

  • усложнение тестовых данных должно происходить постепенно;

  • возникающие затруднения следует четко разделять и устранять строго поочередно.

        Процесс тестирования можно разделить на три этапа.

1. Проверка в нормальных условиях. Предполагает тестирование на основе данных, которые характерны для реальных условий функционирования программы.

2. Проверка в экстремальных условиях. Тестовые данные включают граничные  значения области изменения входных переменных, которые должны восприниматься программой как правильные данные. Типичными примерами таких значений являются очень маленькие или очень большие числа и отсутствие данных. Еще один тип экстремальных условий – это граничные объемы данных, когда массивы состоят из слишком малого или слишком большого числа элементов.

3. Проверка в исключительных ситуациях. Проводится с использованием данных, значения которых лежат за пределами допустимой области изменений. Известно, что все программы разрабатываются в расчете на обработку какого-то ограниченного набора данных. Поэтому важно получить ответ на следующие вопросы:

  • что произойдет, если программе, не рассчитанной на обработку отрицательных и нулевых значений переменных, в результате какой–либо ошибки придется иметь дело как раз с такими данными?

  • как будет вести себя программа, работающая с массивами, если количество их элементов превысит величину, указанную в объявлении массива?

  • что произойдет, если числа будут слишком малыми или слишком большими?

Наихудшая ситуация складывается тогда, когда программа воспринимает неверные данные как правильные и выдает неверный, но правдоподобный результат. Программа должна сама отвергать любые данные, которые она не в состоянии обрабатывать правильно. Не нужно считать причиной ошибок машину, так как современные машины и трансляторы обладают чрезвычайно высокой надежностью.

При конструировании программы необходимо определить адекватный задаче способ задания исходных данных. Отмстим несколько различных способов задания исходных данных, которые рекомендуется применять при тестировании пользовательских программ:

  • ввод с клавиатуры в текстовом режиме (в ответ на программный запрос, указывающий, как правило, содержательное название данного и множество допустимых значений):

  • генерация в программе случайных чисел, задающих, как правило, элементы составных данных (массивов, файлов):

  • генерация данных определенной структуры или с определенными свойствами (например, двоичные деревья) с помощью специальных процедур (генераторов тестов);

  • тестовые файлы (как правило, небольшого размера), содержащие специально подобранную последовательность элементов, на которых наглядно демоне фи русте я исполнение алгоритма;

  • тестовые файлы большого размера (с произвольными или обладающими определенными свойствами данными) для получения количественных оценок алгоритма (например, для сравнения трудоемкости алгоритмов сортировки);

  • произвольные пользовательские файлы, имена которых запрашиваются программой:

  • графические объекты, вводимые с помощью графического курсора и клавиш.

В зависимости от целей программы исходные данные могут отображаться на экране программой или оставаться скрытыми от пользователя. В одной и той же программе можно предусмотреть несколько способов задания исходных данных. Важно, чтобы способ задания исходных данных был адекватен задаче, естествен для нее.

При тестировании можно планировать проверку всех возможных маршрутов исполнения программы при всех значениях исходных переменных. Однако это реализуемо только для очень простых программ небольшого объема при малых диапазонах изменения исходных данных. Поэтому при планировании отладки программ применяются критерии полноты тестирования, которые, однако, не гарантируют полной проверки программ. Выбор критерия для конкретного применения зависит от наличия ресурсов для тестирования и структурной сложности отлаживаемой программы. Критерии характеризуются глубиной контроля программ и объемом проверок. В процессе отладки основная часть неисправностей в программах обнаруживается и затем устраняется. Однако всегда есть риск пропуска нескольких неисправностей.

В современных программных системах (Turbo Basic, Turbo Pascal, Turbo C и др.) отладка осуществляется часто с использованием специальных программных средств, называемых отладчиками. Эти средства позволяют исследовать внутреннее поведение программы.

Программа–отладчик обычно обеспечивает следующие возможности:

  • пошаговое исполнение программы с остановкой после каждой команды (оператора);

  • просмотр текущего значения любой переменной или нахождение значения любого выражения, в том числе, с использованием стандартных функций; при необходимости можно установить новое значение переменной;

  • установку в программе «контрольных точек», т.е. точек, в которых программа временно прекращает свое выполнение, так что можно оценить промежуточные результаты, и др.

Требования к тестированию программ сформулированы в виде аксиом тестирования в известной книге Г. Майерса «Искусство тестирования программ».

Аксиома 1. Считайте тестирование ключевой задачей Вашей разработки.

Эта аксиома, сформулированная в основном для больших, сложно структурированных программ, имеет важное значение и для небольших, учебных программ. Ее утверждение исходит не только из того, что процесс тестирования при надлежащем его выполнении является довольно длительным по времени. Тестирование – очень ответственный этап разработки, так как именно от его выполнения зависит правильность и надежность получаемой в итоге программы Кроме того, как правило, в процессе тестирования учебных программ выясняется необходимость выполнения ряда доработок программы, связанных с оценкой

  • интерфейса (удобства ввода данных и их контроля, точности и полноты выдаваемых сообщений);

  • приемлемости времени исполнения программы;

  • отслеживания программой всех возможных вариантов решения задачи;

  • необходимого представления (типа) данных и точности вычислений.

Вывод, который должен сделать для себя разработчик программы на основе ной аксиомы, состоит в том, что при планировании разработки программы нужно отводить больше времени и внимания данному этапу и очень ответственно выполнять его.

Аксиома 2. Тестирование, кон почти всякая другая деятельность. отмена начинается с постановки целей.

Цели тестирования для учебных программ весьма скромны – показать, что программа при ее исполнении ведет себя правильно, в соответствии с решаемой задачей, т.е. выдает правильные результаты для допустимых исходных данных и сообщает о невозможности их обработки (желательно на ранней стадии обработки) для неверных данных или их недопустимой комбинации. Осознание этих целей должно побудить разработчика спланировать достаточно полный пакет тестов, а также сроки разработки с учетом сложности тестирования программы.

Аксиома 3. Необходимая часть всякого теста описание ожидаемых выходных данных.

Эта аксиома основана на определении теста как двух наборов данных –исходных данных и ожидаемых результатов работы программы. Даже если тестирование не документируется (например, если исходные данные теста вводятся с клавиатуры, а результаты выдаются на экран), то перед тем, как вводить данные или в процессе их ввода, нужно обязательно предсказать ожидаемые результаты работ программы.

Аксиома 4. Подготовка тестов, как для правильных, так и для неправильных входных данных.

Под правильными данными здесь понимаются данные таких типов, диапазонов, форм задания размеров, которые допускает программа. Однако, программа будет правильной (надежной), если она будет адекватно воспринимать и недопустимые данные, т.е. контролировать правильность задания данных как в отдельности, так и в совокупности (возможные наборы значений), и в случае неправильного задания данных, выдавать об этом вразумительные сообщения или выполнять некоторые действия.

Аксиома 5. Проектирование тестов требует даже большего творчества, чем разработка программ.

Известно, что никакое, даже очень тщательное тестирование программы, не может гарантировать отсутствия в ней ошибок. Тем не менее тщательная подготовка пакета тестов в значительной мере обеспечит ее правильность и надежность. Пакет тестов представляет собой совокупность тестов (исходные данные и ожидаемые результаты), по возможности охватывающих все случаи задания исходных данных задачи. Это в частности, означает, что в пакете тестов должны быть тесты, задающие как допустимые, гак и недопустимые программой значения исходных данных, находящиеся

  • внутри допустимого интервала (множества),

  • на каждой из границ интервала.

  • вне допустимого интервала.

Кроме того, должны быть рассмотрены все «вырожденные» случаи задания исходных данных:

  • пустые строки, множества и файлы.

  • последовательности (представляемые массивами) нулевой длины и длины, превышающей допустимую программой (по каждому из измерений массива).

При создании тестов для программ вычислительного характера следует обратить особое внимание на подготовку тестов, проверяющих достижение точности вычислений гарантируемой выбранным численным методом.

Важно также включать в тесты такие максимальные значения исходных данных, которые контролируются программой и указываются в формулировке задачи.

При создании тестов для программ, реализующих алгоритмы поиска, сортировки и других алгоритмов комбинаторного характера следует обратить особое внимание на подготовку тестов, с помощью которых можно определить максимальное (или близкое к нему) время выполнения программы. Для этого можно генерировать последовательности (файлы) большою объема или специальным образом организованные последовательности (для которых проверяемый алгоритм выполняется «неэффективно»).

Аксиома 6. Нужно избегать невоспроизводимых тестов, не тестировать «с лету».

Когда исходные данные теста задаются для того, чтобы посмотреть, «что получится» – это неряшливая и бессмысленная работа. Даже если прогон тестa не документируется. ввод его исходных данных с клавиатуры должен быть осмысленным: это должны быть данные, которые можно воспроизвести еще pаз т.е. представления данных (числовые, строковые) должны быть короткими. Однообразными, подчиненными каким–либо правилам, одним словом, запоминающимися.

Аксиома 7. В пакете тестов не должно быть случайных или несущественных тестов. Хорош тот тест, для которого высока вероятность обнаружить ошибку, а не тот, который демонстрирует правильную работу программы.

Эта аксиома выражает суть тестирования как процесса обнаружения ошибок. Процесс тестирования учебной программы можно считать относительно завершенным не тогда, когда «прошел» первый (или второй или десятый) тест, а когда Вы исчерпали все приводящие Вам в голову варианты задания исходных данных и на всех этих вариантах программа выдала ожидаемые (т. е. правильные) результаты.

Аксиома 8. Детально изучите результаты каждого теста. Самые и ширенные тесты ничего не стоят, если их результаты удостаиваются лишь беглого вклада.

Лучшим средством анализа результатов тестирования является документирование результатов (запись их в файл) и последующее их сравнение с ожидаемыми (тоже задокументированными) результатами. Это сравнение нетрудно выполнять автоматически некоторой программой, даже если сравниваемые данные могут совпадать не в точности, а с некоторой прогнозируемой погрешностью (например, вещественные числа). Но если делается даже простои визуальный анализ выдаваемых на экран значений, он должен быть тщательным и исчерпывающим. Непременным требованием при этом должно быть сохранение на экране исходных данных теста (а иногда и формулировки задачи) для того, чтобы можно было воспроизвести ожидаемые результаты.

Аксиома 9. Никогда не изменяйте программу, чтобы облегчить ее тестирование

Изменение программы при тестировании должно быть следствием глубокого анализа того, почему программа выполнилась так, а не иначе.

Должно быть найдено объяснение всех результатов. И только после этого, поняв, как нужно исправить программу (не ухудшая ее экономичности и надежности), можно приступать к ее изменению. Изменения должны быть по возможности локальными, не менять общую логику программы и те ее части, которые уже отлажены. Радикальное изменение программы означает ее перепроектирование, т.е. возвращение на более раннюю стадию разработки. В любом случае, после каждого (даже сугубо локального) изменения программы должен быть повторен прогон всех использованных ранее тестов.

Анонима 10 По мере того, как растет число обнаруженных ошибок одновременно растет также относительная вероятность существования в ней необнаруженных ошибок

Возрастание числа обнаруживаемых ошибок в программе при ее тестировании обычно обуславливается следующими обстоятельствами.

Если программа изначально составлена (спроектирована) очень плохо, так что никакие ее локальные исправления, выполняемые при тестировании и отладке, не могут ее скорректировать. В этом случае необходимо вернуться к ее перепроектированию, отбросив, возможно полностью, старый вариант программы. Неправильные изменения программы в процессе ее тестирования могут все более отдалять Вас от правильного варианта. Выход из этой ситуации – вернуться к одному из предыдущих вариантов программы. Для этого рекомендуется при тестировании и отладке время от времени (перед существенным се изменением) сохранять вариант текста программы, как-то идентифицируя (например, номером) разные его варианты.