При проектировании структуры программы имеется несколько стратегий разбиения на модули, причем эти стратегии применяются последовательно. Разбиение «исток – преобразование – сток» предполагает деление задачи на функции, занимающиеся получением данных, изменением их формы и затем доставкой их в некоторую точку вне задачи. Функциональное разбиение – это деление задачи на функции, выполняющие конкретные преобразования данных.
Тема 53. Понятие о принципах тестирования программ.
Согласно |
мнению |
экспертов |
основное |
время |
при |
программировании тратится на тестирование и отладку. |
|
||||
Отладка – |
это процесс действий, которые необходимо |
||||
выполнить, когда точно известно, что программа не работает. |
|
||||
Тестирование |
– это |
последовательные и |
систематические |
||
попытки добиться ошибки от программы, которая считается работающей. При этом тестирование может показать только наличие ошибок, но не их отсутствие.
Тестирование в процессе создания программ.
Простейшие свойства программы можно проконтролировать на этапе её создания. В результате программный код пройдет первый круг тестирования ещё до компиляции, и ошибки определенных видов никогда не появятся.
Одним из важнейших методов тестирования является тестирование граничных условий. Большинство ошибок возникает на границах – при каких-то экстремальных значениях. Если при экстремальных значениях код работает корректно, то он, скорее всего, будет корректно работать и повсюду.
int i;
char s[MAX];
for (i=0,(s[i]=getchar())!=’\n’ && i<MAX-1;i++)
;
s[i]=’\0’;
В данном примере не обрабатываются строки, не содержащие
‘\n’.
Пример:
int factorial(int n)
{
int fac; fac = 1; while (n--)
fac *= n; return fac;
}
Программирование на языке высокого уровня 09.03.01 |
66 |
Полезно вставлять некоторый код для обработки ситуаций, которых теоретически не должно быть, но которые могут возникнуть в разных ситуациях.
Также необходимо проверять значение, возвращаемое функцией даже в тех ситуациях, когда для работы программы достаточно вызывать функцию в качестве оператора.
Систематическое тестирование.
Постепенное тестирование каждого написанного модуля существенно лучше тестирования методом «большого скачка», когда сначала пишется вся программа, а затем тестируется целиком. Каждый модуль после написания должен быть оттестирован, а после включения любого модуля в цепочку работающих модулей необходимо оттестировать взаимодействие.
При тестировании отдельного модуля в первую очередь тестированию подлежат самые простые и чаще всего исполняющиеся блоки, при этом на каждом этапе объём тестируемого кода должен увеличиваться. При таких тестах помимо граничных условий систематически тестируются отдельные случаи. Например, при тестировании работы двоичного поиска в целочисленном массиве нужно протестировать все отдельные случаи в массиве, содержащем не менее 5 элементов. Количество случаев, которые необходимо протестировать достаточно велико, чтобы написать программу,
которая |
автоматически |
генерирует |
массив, |
подвергающийся |
тестированию. |
|
|
|
|
Даже |
при разработке самых |
простых |
программ может |
|
понадобиться большое количество тестов. Например, модуль, решающий квадратное уравнение должен быть подвергнут не менее, чем семи тестам, и это не считая проверки диапазонов арифметических значений: a=b=c=0; a=b=0, c=10; a=0, b=5, c=17; a=1, b=6, c=2; a=3, b=7, c=0; a=3, b=2, c=5; a=7, b=c=0.
Рассмотрим набор тестов для полной проверки программы, вводящей три целых числа и печатающей сообщение о том, является ли треугольник разносторонним, равнобедренным или равносторонним. 54% программистов выполняют только одну проверку на равнобедренный треугольник, только 28% программистов три раза проверяют неравенство треугольника, а 44% вообще не проверяли неравенство треугольника. 30% не пробовали подавать на вход не
числовые данные. |
|
|
|
|
|
При |
проведении |
тестов |
необходимо |
знать |
правильный |
результат, даже там где этот результат получить трудно. Если в программе выполняются какие-либо обратимые действия, то надо убедиться, что данные после их обработки можно обратить в исходное состояние.
Программирование на языке высокого уровня 09.03.01 |
67 |
Если существует несколько независимых реализаций той или иной программы, то они должны давать одинаковые результаты на одних и тех же тестах.
Каждое выражение в программе должно быть выполнено хотя бы один раз при проведении последовательности тестов.
Стрессовое тестирование.
Под стрессовым тестированием понимается проверка программ большими объемами данных, сгенерированными компьютером. Большие объемы сами по себе могут стать причинами сбоев, вызывая переполнение буферов ввода, массивов, счетчиков. Большие объемы данных очень полезны при поиске неоправданных ограничений в размерах структур данных. Если вводить только осмысленные, реалистичные данные, то большинство ошибок ввода никогда не случится, и, следовательно, обрабатывающий их код не будет исполнен, а он может быть ошибочным. Но важно не доводить дело до абсурда и не тратить время на исправление ошибок в ситуациях, когда их возникновение крайне маловероятно.
Некоторые виды тестов основаны на введении преднамеренно некорректных данных, так как любой неконтролируемый ввод является потенциальной лазейкой для взлома системы. Ещё одной причиной переполнения может стать преобразование типов.
Хорошие тесты и тестовые случаи часто могут быть использованы для большого количества программ. Например, каждая программа, читающая файлы должна быть проверена вводом пустого файла. Каждая программа, читающая текст, должна быть оттестирована двоичным вводом. Каждая программа, читающая строки текста, должна быть проверена вводом очень длинных строк, пустых строк и файлом без символа перевода строки вообще.
Автоматизация тестирования.
При большом количестве тестов, которые необходимо выполнить, полезно написать программу, которая последовательно запускает эти тесты. Одной из основных форм автоматизации является возвратное тестирование, при котором выполняется последовательность тестов, сравнивающих очередную новую версию программы с предыдущей. Основное назначение возвратного тестирования – убедиться в том, что поведение программы изменилось только в предусмотренных рамках.
В дополнение к возвратным тестам полезно использовать и замкнутые тесты, которые содержат в себе и вводимые данные, и ожидаемые результаты.
Существуют также инструменты, которые взаимодействуют с программой во время ее выполнения. Их основная цель – измерить
качество |
тестирования, определить, в какой мере тесты проверяют |
|
алгоритм |
программы. Например, можно контролировать выполнение |
|
Программирование на языке высокого уровня 09.03.01 |
68 |
|
каждой подпрограммы, подсчитывая, сколько раз она вызывалась. Можно также учесть, сколько раз выполнялся каждый оператор исходной программы или, во всех ли направлениях выполнялся каждый условный переход.
Часто такая статистика накапливается в отдельном файле или базе данных, что полезно при комплексном тестировании системы.
Для автоматизации тестов разрабатываются также специальные языки.
Исполнители тестов
Тестирование, проводимое создателем кода или кем-то другим, имеющим, тем не менее, доступ к исходному коду, называется тестированием белого ящика. При таком тестировании необходимо отрешиться от содержания самого программного кода и придумывать как можно более изощренные проверки. Цель тестирования – найти ошибки, а не объявить программу работающей. Следовательно, тесты должны быть жесткими, и если использование таких тестов приводит к обнаружению проблем, то это является доказательством действенности избранной стратегии тестирования.
Тестирование черного ящика означает, что тестер не имеет доступа к коду и не представляет себе его внутренне устройство. Стандартная последовательность действий при таком тестировании – проверка граничных условий, проверка больших объемов, некорректный ввод. При этом необходимо проверить и работу программы в нормальных условиях.
Фактически, реальные пользователи также тестируют программы. Создание бета-версий программ – это как раз попытка привлечь к тестированию большое число конечных пользователей. При этом часто новые пользователи находят новые ошибки, потому что они опробуют программу неожиданными способами. Но перед распространением бета-версий необходимо провести тестирование белого ящика и тестирование черного ящика.
На всех стадиях и этапах тестирования, когда используются автоматизированные тесты, эти тесты также предварительно должны быть оттестированы.
При этом, главное правило тестирования – делать его.
Тема 54. Отладка программ.
Для отладки подавляющее большинство современных сред программирования включают в свой состав специальные программы – отладчики, предоставляющие программисту широкий спектр возможностей. При этом многие программисты предпочитают использовать метод отладочной печати.
Типовыми советами при отладке программ могут быть:
Программирование на языке высокого уровня 09.03.01 |
69 |
-необходимо проверить соответствие форматов при вводевыводе;
-необходимо убедиться в отсутствии неинициализированных локальных переменных;
-при обнаружении ошибки необходимо проверить отсутствие подобной ошибки в других частях программы;
-необходимо просмотреть стек вызовов функций;
-необходимо попытаться объяснить свой код кому-нибудь
|
ещё. |
|
|
|
|
Для |
полноценной |
отладки |
необходимо |
сделать |
ошибку |
воспроизводимой, при этом следует добиться как можно меньшего объёма входных данных, приводящих к неработоспособности программы. Очень полезным является ведение журнального файла.
Также следует регистрировать любым способом все |
действия, |
которые производятся над программой в процессе отладки. |
|
Согласно статистике, большая часть проблем |
заключается |
именно в некорректном коде, однако крайне редко проблемы могут быть в используемом компиляторе, или даже в операционной системе.
Если при добавлении отладочного кода ошибка перестает проявляться, то проблема, скорее всего, связана с распределением памяти.
Если программа не работает у одного пользователя и работает у другого, то проблема часто бывает связана с правами доступа пользователей или с настройками на их компьютерах.
Тема 55. Понятие о надежности программного обеспечения.
Для обеспечения корректности и надежности работы сложных систем большое значение имеют различные методы верификации и валидации, позволяющие выявлять ошибки на разных этапах разработки и сопровождения программного обеспечения, чтобы последовательно устранять их. Верификация и валидация являются видами деятельности, направленными на контроль качества программного обеспечения и обнаружение ошибок в нем. Имея общую цель, они отличаются источниками проверяемых в их ходе свойств, правил и ограничений, нарушение которых считается ошибкой.
Верификацией называется проверка соответствия результатов отдельных этапов разработки программной системы требованиям и ограничениям, сформулированным для них на предыдущих этапах. В частности, верификация проверяет соответствие между нормами стандартов, описанием требований (техническим заданием) к ПО, проектными решениями, исходным кодом, пользовательской документацией и функционированием самого ПО. Кроме того, проверяется, что требования, проектные решения, документация и код оформлены в соответствии с нормами и стандартами, принятыми
Программирование на языке высокого уровня 09.03.01 |
70 |