Опубликован: 05.11.2013 | Доступ: свободный | Студентов: 543 / 46 | Длительность: 11:51:00
Лекция 8:

Тестирование программного обеспечения

< Лекция 7 || Лекция 8: 123 || Лекция 9 >

7.3. Тестирование. Метод "черного ящика"

Тестирование по требованиям или тестирование "черного ящика" подразумевает неиспользование сведений о структуре исходного кода. Все тестовые примеры составляются только на основе требований, т.е. мы не видим, что находится внутри SUT и как оно работает. Единственное, что доступно - это то, что SUT должно делать, внешние эффекты поведения программного обеспечения.

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

Рассмотрим, например, следующее требование к функции умножения двух целых чисел.

Если входное значение хотя бы одного множителя выходит за гра-ницы диапазона [15 ... 1500], то функция должна вернуть значение 0, в противном случае функция должна вернуть значение произведения двух множителей.

Для тестирования этого требования (если быть точнее, то двух требований) необходимо проверить значения множителей как из диа-пазона [15 ... 1500], так и вне его.

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

В табл. 7.1 представлены все комбинации двух входов, каждый из которых принимает по три различных значения (метод трех точек), так как диапазон [15 ... 1500] с точки зрения сложения чисел не имеет критических точек, кроме своих концов.

Таблица 7.1. Часть тест-плана
Входы Действия Ожидаемый выход
Множитель 1 Множитель 2
15 15 Вызов функции 225
15 700 Вызов функции 10500
15 1500 Вызов функции 22500
700 15 Вызов функции 10500
700 700 Вызов функции 490000
700 1500 Вызов функции 1050000
1500 15 Вызов функции 22500
1500 700 Вызов функции 1050000
1500 1500 Вызов функции 2250000
14 14 Вызов функции 0
1501 14 Вызов функции 0
14 1501 Вызов функции 0
14 700 Вызов функции 0
700 14 Вызов функции 0
1501 700 Вызов функции 0
700 1501 Вызов функции 0

Для проверки поведения функции за границами диапазона стоит проверить, например, значения 14 и 1501 для каждого входа.

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

Метод тестирования "черного ящика" выявляет все несоответствия между требованиями к ПО и поведением самого ПО.

7.4. Тестирование. Метод "белого ящика"

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

Например, для написанного ниже фрагмента программы, где A, B и C рассматриваются как входные значения:

X = 0;
if ((A<=B) || (A>C)) X = 5;  
    

достаточно одного тестового примера (ТП1: A=1, B=2, C=3). В этом случае выполнятся все операторы. Но если программист допустил ошибку и неверно написал условие, например так:

if ((A<=B) || (A>B)) X = 5;  
    

то тогда код будет работать неверно (переменной X всегда будет присваиваться значение 5), хотя показанный выше тестовый пример приведет к выполнению всех операторов и не выявит ошибки.

Для выявления таких ошибок требуется выполнить другой уровень покрытия - по условиям.

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

ТП1: A=1, B=2, C=3;

ТП2: A=3, B=2, C=3.

Эти тестовые примеры позволяют найти ошибку.

Существуют и другие виды покрытия [11, 12, 13].

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

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

Одной из причин может быть несовершенство тест-плана. Другой - пробелы в требованиях. И в том и в другом случае сам тестируемый код может не требовать изменений, но должны быть дописаны новые требования или изменены уже существующие и/или расширен тест-план. В обоих случаях процесс верификации повторяется.

< Лекция 7 || Лекция 8: 123 || Лекция 9 >