Добавлен: 20.05.2023
Просмотров: 437
Скачиваний: 4
1.3 Минимальное грубое тестирование
Обзор критериев белого ящика, подводит к необходимости построения некоторого компромиссного критерия, который, с одной стороны, обеспечивал бы достаточную надежность тестирования, а с другой - имел приемлемую сложность. В качестве такого компромисса был предложен критерий минимально грубого тестирования (МГТ). МГТ представляет собой критерий покрытия решений/условий, усиленный дополнительными требованиями по проверке циклов. Проверка циклов организуется по следующим правилам:
1) для каждого цикла с предусловием должна быть проверена
правильность при кратном нулю, однократном и многократном повторении тела цикла. Многократным считается любое повторение более одного раза;
2) для каждого цикла с постусловием должна быть проверена
правильность при однократном и многократном повторении
тела цикла;
3) проверка цикла со счетчиком зависит от того, фиксированы
ли границы изменения счетчика или вычисляются. Вообще
говоря, как и для цикла с предусловием, требуется проверка
при нулькратном, одно- и многократном повторении тела
цикла.
Одно из преимуществ критерия МГТ состоит в том, что для него существует удобное представление в форме таблицы, которое позволяет контролировать степень выполнения критерия и придумывать тесты прицельно для проверки именно нужных частей программы. Строится таблица МГТ следующим образом.
Строки таблицы соответствуют проверяемым условиям, графы — тестам. Для каждого условного оператора в таблице МГТ создаются 2 строки: для ветви «то» и ветви «иначе».
Пример таблица 1:
Таблица 1
|
Тест 1 |
Тест 2 |
Тест 3 |
Тест 4 |
Тест 5 |
||
|
If a>b |
+ |
|||||
|
- |
Для каждого цикла с предусловием — 3 строки: для кратного нулю, однократного и многократного повторения тела цикла. Пример таблица 2:
Таблица 2
|
Тест 1 |
Тест 2 |
Тест 3 |
Тест 4 |
Тест 5 |
||
|
While a>b |
=0 |
|||||
|
=1 |
||||||
|
>1 |
Для каждого цикла со счетчиком — 3 строки: для кратного нулю, однократного и многократного повторения тела цикла.
В случае разбиения программы на процедуры, модули и т. п. МГТ-таблицы строятся для каждой процедуры, модуля и пр. Соответственно, тестирование проводится прицельно для данной процедуры, для данного модуля.
Критерий МГТ не идеален, как и все предыдущие. Он не гарантирует проверку комбинации всех простых условий. Он не гарантирует надежную проверку циклов. Приведенный в предыдущей части пример 3, который «ломал» критерий решений/условий, «сломает» и критерий МГТ. Выполнение требований минимально грубого тестирования не гарантирует проверку всех возможных комбинаций простых условий. Ошибка в примере 2, выявление которой не гарантировали критерии покрытия ветвей, решений/условий и комбинаторного покрытия условий, может быть пропущена и критерием МГТ. Тем не менее, критерий МГТ представляется достаточно разумным компромиссом между надежностью и сложностью тестирования.
Глава 2. ОШИБКООПАСНЫЕ СИТУАЦИИ
Ни один из критериев полноты тестирования, описанных ранее и применимых на практике, не дает стопроцентной гарантии отсутствия ошибок. Поэтому в дополнение к критериям рекомендуется еще один способ поиска ошибок в программе. Это просмотр текста программы для выявления и проверки ситуаций, при которых могут возникнуть ошибки. Далее приводится список основных ситуаций. Список, к сожалению, не исчерпывающий.
2.1 Обращение к данным
1. Использование значения переменной.
Опасность: Неинициализированная переменная. (Переменная используется до того, как ей было присвоено значение.)
Очень частая ошибка начинающих программистов. Признаком ее служит появление у переменных неожиданных «мусорных» значений (очень больших чисел, чисел с громоздкой дробной частью, строк, забитых «мусором», и пр.). К сожалению, обнаруживать эту ошибку автоматически умеют очень немногие вычислительные системы.
2. Автоматическая инициализация переменных.
Опасность: Неверная инициализация.
Некоторые системы программирования автоматически заполняют выделяемую память стандартными значениями, чаще всего нулями. Всегда или при включении соответствующего режима. Проверьте, делает ли это ваша система. Использует ли она нужное вам значение? Можно ли управлять процессом инициализации?
- Индексация массива.
Опасность: Выход индекса за границу измерения.
- Изменение переменной внутри блока.
Опасность: Побочный эффект (изменение глобальной переменной при выполнении подпрограммы).
В языках с блочной структурой это не является ошибкой, но требует повышенного внимания. Ведь по внешнему виду вызова процедуры или функции никак нельзя сказать, какие глобальные переменные будут изменены при ее выполнении.
- Использование значения ссылочной переменной.
Опасность: «Висячая ссылка».
Переменная ссылочного типа указывает на область памяти, которая уже возвращена системе. Особенно неприятно, в случае если эта область уже будет перераспределена под другую переменную.
- Схожие имена переменных.
Само по себе это не ошибка. Но может быть причиной описки. Соответственно требует повышенного внимания.
- Использование записи с вариантами.
Опасность: Несколько полей записи с вариантами используются для обращения к одной и той же области памяти при отсутствии контроля за типизацией.
Само по себе это не ошибка. Но может оказаться, что эти поля имеют разные типы. В этом случае величина, записанная как значение одного типа, может быть прочитана или откорректирована как значение другого типа.
- Использование не типизированного указателя.
Опасность: Еще одна возможность обойти типовой контроль. Динамическая переменная, на которую ссылается данный указатель, в разных местах программы может трактоваться как переменная разных типов.
9. Использование переменных, не имеющих явного описания.
Ряд языков не требует явного описания переменных. В любой точке программы вы можете вставить в текст программы новое имя и тем самым создать новую переменную. Подобное неявное описание требует повышенного внимания по трем причинам. Во-первых, оно опасно с точки зрения описок. Неверно введенное имя будет просто воспринято как неявное описание новой переменной. Во-вторых, имеет смысл уточнить, какой тип приписывается по умолчанию автоматически создаваемой переменной (если приписывается). В-третьих, стоит уточнить, какова область действия (область видимости) автоматически созданной переменной.
2.2 Вычисления
1. Выражение
Опасность: Неверный порядок вычисления операций в выражении.
Пример:
int a =2;
int v = ++a + ++a * ++a;
Математик будет ожидать умножения, а потом сложения. Хотя умножение выполняется перед сложением, первыми вычисляются операнды оператора ++. Таким образом, выражение равно 3+4*5, или 23.
Особенно опасно непонимание порядка выполнения операций в сочетании с отсутствием строгого типового контроля.
- Логическое выражение
Опасность: Путаница между полной и краткой схемами вычисления логических выражений.
Одно из отличий логических вычислений от арифметических в том, что возможных результатов всего два — «истина» и «ложь». Поэтому очень часто результат выражения становится ясен без выполнения всех вычислений. Если первое слагаемое в дизъюнкции истинно или первый сомножитель в конъюнкции ложен, остальные можно уже не вычислять. С точки зрения математики совершенно неважно, прервем мы вычисления после первого слагаемого (сомножителя) или будем продолжать дальше. Но в программировании это может быть важно.
Краткая схема вычисления логических выражений означает, что вычисления будут прерваны, как только будет ясен результат. Полная — что выражение вычисляется до конца, независимо от промежуточных результатов. Схема вычисления может быть зафиксирована в языке, а может регулироваться в системе программирования.
- Сравнения > / <
Опасность: Потеря третьего результата операции сравнения.
В математике сравнение двух чисел может иметь 3 исхода: больше, меньше, равно. В языках программирования операции сравнения — логические, т. е. имеющие только 2 исхода. Третий исход зачастую оказывается потерянным. Для «полноценного» сравнения требуется не один условный оператор, а два вложенных:
if (a>b) {…} else { if (a=b) { …} else {a<b} …}
- Сравнения> и >= , < и <=
Опасность: Ошибки типа «±1».
Частая ошибка — путаница сравнений на строгое и нестрогое неравенство: > и >=, < и <=. Если сравнение стоит в заголовке цикла, то он будет повторяться на один раз больше или меньше требуемого при неправильном выборе знака сравнения. Отсюда и название типа ошибки.
- Деление
Опасность: Деление на нуль.
Убедиться (приведите правдоподобные рассуждения в пользу того), что выражение в знаменателе не может оказаться равным нулю.
- Извлечение квадратного корня
Опасность: Корень из отрицательного числа.
Аргумент не должен получить недопустимое значение.
- Взятие логарифма
Опасность: Логарифм неположительного числа.
Убедитесь, что аргумент не может получить недопустимое значение.
- Использование в вычислениях данных «не того» типа
Опасность: Неверное приведение типов данных.
Например, использование литерных значений в арифметических операциях или целочисленных значений — в логических. Строго типизированные языки такое запрещают. Но не все языки строго типизированы. В слабо типизированных языках это не обязательно ошибка. Но имеет смысл уточнить, как именно будут выполняться операции. Например, какой результат даст сумма 1 + ‘1’? Чему будет равна литерная единица:
целочисленной единице или коду литеры ‘1’?
- Присваивание целой переменной вещественного значения
Опасность: Способ преобразования вещественного числа в целое.
Само по себе присваивание целой переменной вещественного значения может языком допускаться. При этом проводится автоматическое преобразование вещественного числа в целое. Проводиться оно может двумя путями: округлением или обрубанием дробной части. Какой способ будет использован в вашем случае?
- Вычисления с плавающей точкой (вещественная арифметика)
Опасность 1: Погрешности округления.
Машинные вычисления не всегда совпадают с арифметическими. В первую очередь это относится к вещественным значениям. Причин тому две. Во-первых, в машинной памяти числа хранятся не в десятичном формате, а в двоичном. Преобразование выполняется с некоторым округлением. Во-вторых, точность представления чисел в памяти ограничена. В результате вещественная единица вполне может оказаться равна 0,9999999999, а может - 1,0000000001 (количество знаков после запятой зависит от точности представления).
Пример:
a= 1/3;
b= a*3;
В математике b будет равно 1. В программировании для начала окажется
а=1/4+1/16+1/64+1/256 и т. д. в зависимости от точности представления. Это не совсем одна треть. В конце концов, наберется сумма, которая с заданной точностью даст a = 0,3333333333.Но тогда b = 0,9999999999, а не 1. Если таких значений в выражении будет несколько или выражение многократно пере вычисляется в цикле, ошибка округления будет копиться. К счастью, в большинстве языков счетчик цикла не может быть вещественным. Но поскольку в таких конструкциях есть объективная необходимость, его приходится моделировать.
Опасность 2: Потеря значимости (получение чисел с очень маленькой мантиссой).
Слишком маленькая мантисса в машинной арифметике может превратиться в нуль.
- Сравнение вещественных чисел
Опасность: Погрешности округления.
Погрешности округления чреваты ошибками не только в арифметических операциях (о чем уже было сказано). В операциях сравнения они могут привести к тому, что «лобовое сравнение» вещественных чисел даст неверный результат. Пусть вещественные переменные q и r обе равны единице. Но в одном случае вещественная единица будет представлена как 0,9999999999, а в другом — как 1,0000000001. В этом случае сравнение q r вполне может дать значение «ложь». Лучше сравнивать модуль разности с некоторым eps.
- Арифметические вычисления (как вещественные, так и целые)