Файл: Отладка и тестирование программ: основные подходы и ограничения (Основные этапы проектирования программы).pdf
Добавлен: 30.03.2023
Просмотров: 218
Скачиваний: 2
Наиболее характерными объектами тестирования являются: требования и спецификации, программные модули, группы программ, решающие законченные функциональные задачи.
Существуют три альтернативных варианта тестирования: нисходящее, восходящее и раздельное, отличающиеся порядком кодирования модулей и процедурой передачи данных тестируемым компонентам. Как и в случае проектирования программ, наибольший эффект достигается при совместном использовании этих методов [17].
При восходящем тестировании первыми обычно кодируются и тестируются с помощью «драйверов». Физические модули нижнего уровня, затем тестируются вызывающие их модули и так вплоть до главного модуля. Основные трудности состоят в необходимости обновления тестовых данных при подключении каждого нового модуля более высокого уровня. Однако все модули нижнего уровня тестируются детально и независимо, что устраняет значительное количество ошибок при подключении их к вызывающим модулям.
Передача данных и имитация вызывающих модулей упрощается при использовании специальных программ – тестировщиков.
Такая программа имитирует работу вызывающих модулей и обеспечивает передачу данных в тестируемый физический модуль и из него. Данные, создаваемые физическим модулем, выводятся на печать.
Некоторые программы – тестировщики осуществляют также автоматическую проверку полученных и ожидаемых результатов, многократное тестирование за один прогон и автоматическое исправление ошибок.
После того как составлены и испытаны все физические модули нижнего уровня, тестируются физические модули следующего верхнего уровня, причем совместно с только что проверенными модулями. Этот процесс продолжается до тех пор, пока не будут составлены и оттестированы все физические модули. Управляющий модуль кодируется и тестируется последним. Такой метод наиболее удобен при испытании программ модульной структуры и при наличии квалифицированных программистов [4].
При нисходящем тестировании в первую очередь проверяется главный модуль, к которому постепенно подключаются модули более низких иерархических уровней, при этом так же возможно использование программ – заглушек. При использовании данного метода появляется возможность сохранения и развития исходных тестовых данных по мере подключения модулей нижних иерархических уровней, т.е. с самого начала тестирования могут использоваться реальные исходные данные, которые уточняются по мере подключения модулей. Недостаток: затрудненный поиск ошибок в подключаемых модулях.
Один из вариантов этого подхода состоит в тестировании одной полной ветви программы. Первой проверяется (с использованием при необходимости заглушек) управляющая логика. Некоторые системы реализуются очередями, причем вначале, до полного тестирования программы, обрабатывается некоторое подмножество данных. Такой порядок реализации системы возможен, поскольку при разработке каждой программы нетрудно предусмотреть отдельные ветви для обработки различных данных. Это может оказаться весьма полезным, т. к. часто 10 % обрабатываемых типов данных могут на 90 % обеспечить потребности пользователей [21].
Раздельное тестирование – метод (один из вариантов метода восходящего проектирования) применяется только для раздельно компилируемых физических модулей. Он весьма полезен в тех случаях, когда программу не удается полностью специфицировать, либо когда имеется один критический модуль, на характеристики которого накладываются определенные ограничения, и он должен быть испытан до принятия решения о работоспособности программы. Процедура тестирования разбивается на две стадии:
- автономная разработка каждого физического модуля с имитацией вызывающего модуля и использованием модулей–заглушек;
- совместное редактирование связей уже проверенных модулей – комплексное тестирование [3].
Для оптимизации набора тестов, т.е. для подготовки такого набора тестов, который позволял бы при заданном их числе (или при заданном интервале времени, отведенном на тестирование) обнаруживать большее число ошибок в ПС, необходимо, во–первых, заранее планировать этот набор и, во–вторых, использовать рациональную стратегию планирования тестов. Проектирование тестов можно начинать сразу же после завершения этапа внешнего описания ПС. Возможны разные подходы к выработке стратегии проектирования тестов, которые можно условно графически разместить между следующими двумя крайними подходами. Левый крайний подход заключается в том, что тесты проектируются только на основании изучения спецификаций ПС (внешнего описания, описания архитектуры и спецификации модулей).
Строение модулей при этом никак не учитывается, т.е. они рассматриваются как черные ящики. Фактически такой подход требует полного перебора всех наборов входных данных, т. к. в противном случае некоторые участки программ ПС могут не работать при пропуске любого теста, а это значит, что содержащиеся в них ошибки не будут проявляться. Однако тестирование ПС полным множеством наборов входных данных практически неосуществимо. Правый крайний подход заключается в том, что тесты проектируются на основании изучения текстов программ с целью протестировать все пути выполнения каждой программ ПС. Если принять во внимание наличие в программах циклов с переменным числом повторений, то различных путей выполнения программ ПС может оказаться также чрезвычайно много, так что их тестирование также будет практически неосуществимо [3].
Оптимальную стратегию проектирования тестов можно конкретизировать на основании следующего принципа: для каждого программного документа (включая тексты программ), входящего в состав ПС, должны проектироваться свои тесты с целью выявления в нем ошибок. Во всяком случае, этот принцип необходимо соблюдать в соответствии с определением ПС и содержанием понятия технологии программирования как технологии разработки надежных программ.
Тестирование программных систем не дает тех гарантий их качества, которых требует практика, из–за сильной недетерминированности таких систем. Путем тестирования невозможно установить отсутствие ошибок на всех выполнениях недетерминированной системы, определяемых одним и тем же начальным состоянием. Математическое обоснование надежности программ основано на формальной верификации, которая посредством формального доказательства позволяет устанавливать присутствие требуемых свойств программы для всех допустимых этой программой выполнений. Верификация ПО является почти единственным способом анализа требуемых свойств ПО относительно заданных предусловий [11].
Фундаментом верификации является логика, формальный язык логики, а также формальные модели и методы. Верификация программ обычно сводит анализ их свойств к доказательству истинности условий корректности в виде логических формул.
Основным подходом к обоснованию корректности, является подход, при котором исследуется (верифицируется) не сама программа, а ее спецификация (формальная модель). Представительными из числа широко распространенных формальных моделей являются сети Петри, взаимодействующие последовательные процессы Хоара, временные (темпоральные) логики.
Несмотря на то, что результаты применения верификации значительно мощнее, решающее практическое значение для обоснования надежности последовательных программ имеет тестирование. Это связано с тем, что верификация является очень трудоемким процессом и требует пока больших затрат, а в случае последовательных программ эти затраты часто бывают не оправданы [19].
Отладка – процесс исправления ошибок, обнаруженных при тестировании, состоит из многократного чередования этапов тестирования, локализации и исправления ошибок.
Если при тестировании полученные результаты отличаются от эталонных (ожидаемых), то необходимо определить местоположение ошибки (локализовать ее), ее характер, а затем выработать одну или несколько гипотез о природе ошибок. Важно исследовать полученные данные в поисках противоречий выдвинутым гипотезам. Для получения дополнительных данных используются аварийная печать, печать в контрольных точках и слежение за значениями переменных. При аварийной печати выдаются значения переменных в программе в момент возникновения ошибки. При печати в контрольных точках в программе заранее выбираются места, в которых необходимо распечатать дополнительную информацию. При слежении в момент, когда переменной присваивается новое значение, оно выводится на экран. Во многих системах программирования на языках высокого уровня перечисленные выше возможности включены в символьные отладчики, позволяющие вести отладку в интерактивном режиме [22].
После локализации ошибки целесообразно внимательно проверить весь модуль. Не исключено, что будут выявлены еще какие–то ошибки. Если корректировка требует серьезных изменений, необходимо проанализировать текст программы полностью. В заключение нужно обязательно скорректировать документацию.
Несомненно, что любая ошибка нуждается в пристальном изучении. Необходимо понять, почему она возникла и что должно быть сделано, чтобы ее предотвратить или обнаружить раньше
2.2 Отладка и тестирование программ: основные подходы и ограничения
Рассмотрим подробно основные подходы (методы) к тестированию и отладке программного обеспечения, а также их ограничения.
Метод Сандвича
Тестирование методом сандвича представляет собой компромисс между восходящим и нисходящим подходами. Здесь делается попытка воспользоваться достоинствами обоих методов, избежав их недостатков. При использовании этого метода одновременно начинают восходящее и нисходящее тестирование, собирая программу как снизу, так и сверху и встречаясь в конце концов где–то в середине. Точка встречи зависит от конкретной тестируемой программы и должна быть заранее определена при изучении ее структуры.
Например, если разработчик может представить свою систему в виде уровня прикладных модулей, затем уровня модулей обработки запросов, затем уровня примитивных функций, то он может решить применять нисходящий метод на уровне прикладных модулей (программируя заглушки вместо модулей обработки запросов), а на остальных уровнях применить восходящий метод. Применение метода сандвича – это разумный подход к интеграции больших программ, таких, как операционная система или пакет прикладных программ. Метод сандвича сохраняет такое достоинство нисходящего и восходящего подходов, рассмотренных в предыдущем разделе работы, как начало интеграции системы на самом раннем этапе. Поскольку вершина программы вступает в строй рано, мы, как в нисходящем методе, уже на раннем этапе получаем работающий каркас программы. Поскольку нижние уровни программы создаются восходящим методом, снимаются те проблемы нисходящего метода, которые были связаны с невозможностью тестировать некоторые условия в глубине программы [7].
Модифицированный метод сандвича.
При тестировании методом сандвича возникает та же проблема, что и при нисходящем подходе, хотя здесь она стоит не так остро. Проблема эта в том, что невозможно досконально тестировать отдельные модули. Восходящий этап тестирования по методу сандвича решает эту проблему для модулей нижних уровней, но она может по–прежнему оставаться открытой для нижней половины верхней части программы. В модифицированном методе сандвича нижние уровни также тестируются строго снизу вверх. А модули верхних уровней сначала тестируются изолированно, а затем собираются нисходящим методом. Таким образом, модифицированный метод сандвича также представляет собой компромисс между восходящим и нисходящим подходами [14].
Метод «белого ящика»
Термин «белый ящик» означает, что при разработке тестовых случаев тестировщики используют любые доступные сведения о внутренней структуре или коде. Технологии, применяемые во время тестирования «белого ящика», обычно называют технологиями статического тестирования. Этот метод не ставит цели выявление синтаксических ошибок, так как дефекты такого рода обычно обнаруживает компилятор. Методы белого ящика направлены на локализацию ошибок, которые сложнее выявить, найти и зафиксировать. С их помощью можно обнаружить логические ошибки и проверить степень покрытия тестами.
Тестирование посредством белого ящика, как правило, включает в себя стратегию модульного тестирования, при котором тестирование ведется на модульном или функциональном уровне и работы по тестированию направлены на исследование внутреннего устройства модуля. Данный тип тестирования называют также модульным тестированием, тестированием прозрачного ящика или прозрачным тестированием, поскольку сотрудники, проводящие тестирование, имеют доступ к программному коду и могут видеть работу программы изнутри. Данный подход к тестированию известен также как структурный подход. На этом уровне тестирования проверяется управляющая логика, проявляющаяся на модульном уровне. Тестовые драйверы используются для того, чтобы все пути в данном модуле были проверены хотя бы один раз, все логические решения рассмотрены во всевозможных условиях, циклы были выполнены с использованием верхних и нижних границ и роконтролированы структуры внутренних данных.
Методы тестирования на основе стратегии белого ящика:
- Ввод неверных значений.
- Модульное тестирование.
- Утечка памяти.
- Тестирование цепочек.
- Исследование покрытия.
- Покрытие решений.
- Покрытие условий [22].
Метод «черного ящика»
Тестирование на основе стратегии черного ящика возможно лишь при наличии установленных открытых интерфейсов, таких как интерфейс пользователя или программный интерфейс приложения (API). Если тестирование на основе стратегии белого ящика исследует внутреннюю работу программы, то методы тестирования черного ящика сравнивают поведение приложения с соответствующими требованиями. Кроме того, эти методы обычно направлены на выявление трех основных видов ошибок: функциональности, поддерживаемой программным продуктом; производимых вычислений; допустимого диапазона или области действия значений данных, которые могут быть обработаны программным продуктом.