Файл: Отладка и тестирование программ: основные подходы и ограничения.pdf

ВУЗ: Не указан

Категория: Курсовая работа

Дисциплина: Не указана

Добавлен: 28.03.2023

Просмотров: 119

Скачиваний: 2

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

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

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

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

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

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

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

Глава 2

Стратегия тестирования и отладки программного обеспечения

2.1 Метод белого ящика

Стратегия белого ящика:

  1. Покрытие операторов
  2. Покрытие решений
  3. Покрытие условий
  4. Покрытие решений/условий

2.1.1 Покрытие операторов

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


2.1.2 Покрытие решений

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

Можно показать, что покрытие решений обычно удовлетворяет критерию покрытия операторов. Поскольку каждый оператор лежит на некатором пути, исходящем либо из оператора перехода, либо из точки входа программы, при выполнении каждого направления перехода каждый оператор должен быть выполнен. Однако существует три исключения. Первое – патологическая ситуация, когда программа не имеет решений. Второе встречается в программах или подпрограммах с несколькими точками входа (например, в программах на языке Ассемблера); данный оператор может быть выполнен только в том случае, если выполнение программы начинается с соответствующей точки входа. Третье исключение – операторы внутри switch-конструкций; выполнение каждого направления перехода не обязательно будет вызывать выполнение всех case-единиц. Так как покрытие операторов является необходимым условием, то покрытие решений, которые представляется более сальным критерием, должно включать покрытие операторов. Следовательно, покрытие решений требует, чтобы каждое решение имело, результатом значения истина и ложь и при этом каждый оператор выполнялся бы, по крайней мере, один раз. Но также есть альтернативный и более легкий способ выражения этого требования, который состоит в том, что каждое решение имело результатом значения истина и ложь и что каждой точке входа (включая также каждую case-единицу) Должно быть предано управления при вызове программы, по крайней мере, один раз.

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

2.1.3 Покрытие условий

Покрытие решений – более сильный критерий, чем покрытие операторов, но и он имеет свои недостатки. Например, путь, где X не изменятся (если выбрано первое альтернативное покрытие), будет проверен с вероятностью 50 %. Если во втором решении существует ошибка (например, X < 1 вместо X > 1), то ошибка не будет обнаружена двумя тестами предыдущего примера.


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

2.1.4. Покрытие решений/условий

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

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


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

Много условные решения исходной программы здесь разбиты на отдельные решения и переходы, поскольку большинство компьютеров не имеет команд, реализующих решений со многими исходами. Наиболее полное покрытие тестами в этом случае осуществляется таким образом, чтобы выполнялись все возможные результаты каждого простого решения. Два предыдущих теста критерия покрытия решений не выполняют этого; они недостаточны для выполнения результата ложь решения H и результата истина решения K. Набор тестов для критерия покрытия условий такой программы также является неполным; два теста (которые случайно удовлетворяют также и критерию покрытия решений/условий) не вызывают выполнения результата ложь решения I и результат истина решения K.

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


2.2 Стратегии черного ящика

Стратегии черного ящика:

  1. Эквивалентное разбиение
  2. Анализ граничных значений
  3. Применение функциональных диаграмм
  4. Предположение об ошибке

2.2.1 Эквивалентное разбиение

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

Правильно выбранный тест должен обладать двумя свойствами:

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

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

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

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

Примером класса эквивалентности для программы является набор “трех равных чисел, имеющих целые значения, больше нуля”. Определяя этот набор как класс эквивалентности, устанавливают, что если ошибка не обнаружена некоторым тестом данного набора, то маловероятно, что она будет обнаружена другим тестом набора. Другими словами хочется сказать, что в этом случае время тестирования лучше затратить на что-нибудь другое.


Разработка тестов методом эквивалентного разбиения осуществляется в два этапа:

  1. Выделение классов эквивалентности
  2. Построение тестов

2.2.1.1 Выделение классов эквивалентности

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

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

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

  1. Если входное условие описывает область значений, то определяются один правильный класс эквивалентности и два неправильных.
  2. Если входное условие описывает число значений, то определяются один правильный класс эквивалентности и два неправильных.
  3. Если входное условие описывает множество входных значений и есть основание полагать, что каждое значение программа трактует особо, то определяется правильный класс эквивалентности для каждого значения и один неправильный класс эквивалентности.
  4. Если входное условие описывает ситуацию “должно быть”, то определяется один правильный класс эквивалентности и один неправильный.
  5. Если есть любое основание считать, что различные элементы класса эквивалентности трактуются программой неодинаково, то данный класс эквивалентности разбивается на меньшей классы эквивалентности.

Построение тестов

Второй шаг заключается в использовании классов эквивалентности для построения тестов. Этот процесс включает в себя:

  1. Назначение каждому классу эквивалентности уникального номер.
  2. Проектирование новых тестов, каждый из которых покрывает как можно большее число непокрытых правильных классов эквивалентности, до тех пор все правильные классы эквивалентности не будут покрыты тестами.
  3. Запись тестов, каждый из которых покрывает один и только дин из непокрытых неправильных классов эквивалентности, до тез пор, пока все неправильные классы эквивалентности, до тех пор, пока все неправильные классы эквивалентности не будут покрыты тестами.