И. Соммервилл - Инженерия программного обеспечения (1133538), страница 107
Текст из файла (страница 107)
Затем вся система тестируется целиком. При восходящем тестировании, наоборот, сначала интегрируются и тестируются модули, расположсппыс па болсс низких уровнях иерархии. Затем выполняется сборка и тестирование модулей, расположенных па верхнем уронив иерархии, и так до тех пор, пока нс будет протсстирован последний модуль. При таком подходе нс трсбуигся наличии эакончснного архитектурного проекта системы, и поэтому он можст начинаться на раннем этапе процесса разработки. Обычно такой подход примснястся тогда, когда в системе есть повторно испольэусмыс компоненты нли модифицированные компоненты издругих систсм. Ннсходящсс и восходлщсс тестирование можно сравнить по чстырсм направлениям.
1. Вериутиппоня и пмписпюрия системной арпипмкшурлс При нисходящем тестировании больше возможностей выявить ошибки в архитектуре системы на раннсм этапе 20. Тесгнрованне программного обеспечения 417 процесса разработки. Обычно это структурные ошибки, раннее выявление которых предполагает их исправление без дополнительных затрат. При восходящем тестировании структура высокого уровня не утверждается вплоть до последнего этапа разработки системы. 2.
э2емонаюрация сипэачьь При нисходящей разработке незаконченная система вполне пригодна для работы уже иа ранних этапах разработки. Этот факт является важным психологическим стимулом использования нисходящей модели разработки систем, поскольку демонстрирует осуществимость управления системой. Аттестация проводится в начале процесса тестирования путем создания демонстрационной версии системы. Но если система создается из повторно используемых компонентов, то н при восходящей разработке также можно создать ее демонстрационную версию. 3. Реалкэачия жесэкы. Нисходящее тестирование сложно реализовать, так как необхо. димо моделировать программы-заглушки нижних уровней. Программы-заглушки могут быть упрощенными версиями представляемых компонентов.
При восходящем тестировании для того, чтобы использовать компоненты нижних уровней, не. обходима разработать тестовые драйверы, которые эмулируют окружение компо. пента в процессе тестирования. 4. Наблюдение зо ходам исяитпкий. При нисходящем н восходящем тестировании могут возникать проблемы, связанные с наблюдениями за кодом тестирования. В боль. шинстве систем, разрабатываемых сверху вниз, более верхние уровни системы, которые реализованы первыми, не генерируют выходные данные, однако для про. верки этих уровней нузкпы какие-либо выходные результаты. Испытатель должен создать искусственную среду для генерации результатов теста.
При восходящем тестировании также может возникнуть необходимость в создании искусственной среды (тестовых драйверов) для исследованил компонснтов нижних уровней. На практике при разработке и тестировании систем чаще всего используется композиция восходящих и нисходящих методов. Разные сроки разработки для разных частей системы предполагают, что группа, проводящая тестирование и интеграцию, должна работать с каким-либо готовым компонентом.
Поэтому во время процесса тестирования сборки в любом случае необходимо разрабатывать как заглушки, так н тестовые драйверы. 20.2.2. Тестирование интерфейсов Как правило, тестирование интерфейса выполняется в тех случаях, когда модули или подсистемы интегрируются в большие системы. Каждый модуль или подсистема имеет заданный интерфейс, который вызывается другими компонентами системы. Цель тестиро.
ванна интерфейса — выявить ошибки, возникающие в системе вследствие ошибок в интерфейсах или неправильных предположений об интерфейсах. Схема тестирования интерфейса показана на рис. 20.11. Стрелки в верхней части схемы означают, что контрольные тесты применяются не к отдельным компонентам, а к подсистемам, пол>ченным в результате кол~бинирования этих компонентов. Данный тип тестирования особенно вюкен в объектно. ориентированном проектировании, в частности при повторном использовании объектов и классов объектов. Объекты в значительной степени определяются с помощью интерфейсов и могут повторно использоваться в различных комбинациях с разными объектами и в разных системах. Во время тестирования отдельных объектов невозможно выявить ошибки интерфейса, так как они являются скорее результатом взаимодействия между объектами, чем изолированного поведения одного объекта.
418 Часть Ч. Верификация и аз гвстация Ркс. 20.1!. Теппкроптше ннтпффейом Между компонентами программы могут быть разные типы интерфейсов и соответственно разные типы ошибок интерфейсов. 1. Ппранемричелхке кнлпффексм. Интерфейсы, в которых ссылки па данньле и иногда функции передаются в виде параметров от одного компонента к др> гому. 2. Ннпмрфейсьл рпздсплвчой ппчлми. Ипгерфейсы, в которых какойлибо блок памяти совместно используется разными подсистемами. Одна подсистема помещает данные в палгятьь а другис подсистемы используют эти данные. Я. Провед>рным инперфейсы.
Интерфейсы. в которых одна подсистема инкапсулирует набор процедур, вызываеллых из других подсистем. Такой тип интерфейса имеют объекты и абстрактные типы данных. 4. Инпмрфгйсм ллгредпчи спобщеник. Ин гсрфсйсы, в которых одна подсистема запраши. наст сервис у другой подсистемы посредством передачи ей сообщения. Ответное сообщение содержит результаты выполнения сервиса. Некоторые объектно. ориентированные системы имеют такой тип интерфейсов; например, так работают системы клиент/сервер. Ошибки в интерфейсах являются наиболее распространенными типами ошибок в сложных системах 12281 и делятся на три класса. ° Нппрпаилькпс ипкмышпкие инмерфгшов.
Компонент вьлзываст другой компонент и совершает ошибку при использовании его интерфейса. Данный тип ошибки особенно распространен в параметрических интерфейсах; например, параметры могут иметь неправильный тип, следовать в неправильном порвдке илн же иметь неверное количество параметров. ° Непрпвкпьпое япнивпкиг изтне~~фтсов. Вызывающий компонсн г, в который заложена неправильная интерпретация спецификации интерфейса вызываемого компонента, предполагает определенное поведение этого компонента. Если поведение вье зываемого компонента не совпадает с ожидаемым, поведение вызывающего компонента становится непредсказуемым, Например, если программа бинарного поиска вызывается для поиска заданного элемента в псупорлдочепном массиве, то в работе программы произойдет сбой.
20. Тестирование программного обеспечения 419 ° 0»лийси апакранц»аяии. Такие ошибки встречаются в системах реального времени, где используются интерфейсы разделяемой памяти или передачи сообщений. Подсистема — производитель данных и подсистема — потребитель данных могут работать с разной скоростью. Если при проектировании интерфейса не учитывать этот фактор, потребитель может, например, получить доступ к устаревшим данным, потому что производитель к тому моменту еще не успел обновить совместно используемые данные.
Тестирование дефектов интерфейсов сложно, поскольку некоторые ошибки могут проявиться только в необычных условиях. Например, пусть некий объект реализует очередь в виде структуры списка фиксированного размера, Вызывающий его объект при вводе очередного элемента не проверяет переполнение очереди, так как предполагает, что очередь реализована как структура неограниченного размера. Такую ситуацию можно обнаружить только во время выполнения специальных тестов: специально вызывается переполнение очереди, которое приводит к непредсказуемому поведению объекта. Другая проблема может возникнуть из-за взаимодействий между ошибками в разных программных модулях нли объектах.
Ошибки в одном объекте можно выявить только тогда. когда поведение другого объекта становится непредсказуемым. Например, для получения сервиса один обьекг вызывает другой объект и полагает, что полученный ответ правильный. Если объект неправильно понимает вычисленные значения, возвращаемое значение может быть достоверным, но неправильным.
Такие ошибки можно вьшвить только тогда, когда оказываются неправильными дальнейшие вычисления. Вот несколько общих правил тестирования интерфейсов. 1. Просмотрите тестируемый код н составьте список всех вызовов, направленных к внешним компонентам. Разработайте такие наборы тестовых данных, при которых параметры, передаваемые внешним компонентам, принимают крайние значения из диапазонов их допустимых значений. Использование экстремальных значений параметров с высокой вероятностью обнаруживает несоответствия в интерфейсах. 2.
Если между интерфейсами передаются указатели, всегда тестируйте интерфейс с пулевыми параметрами указателя. 5. При вызове коипонснта через процедурный интерфейс нспользуйтс тесты, вызывающие сбой в работе компонента. Одна из наиболее распространенных причин ошибок в интерфейсе — неправильное понимание спецификации компонентов. 4. В системах передачи сообщений используйте тесты с нагрузкой, которые рассмат. рпваются в следующем разделе.
Разрабатывайте тесты, генерирующие в несколько раз большее количество сообщений, чем будет в обычной работе системы. Зти жс тесты позволяют обнаружить проблемы синхронизации. 5. Прн взаимодействии нескольких компонентов через разделяемую память разрабатывайте тесты, которые изменяют порядок активизации кол»понентов. С помощью таких тестов можно выявить сделанные програмл»истом неявные предположения о порядке использования компонентами разделяемых данных. Обычно статические методы тестирования более рентабельны, чем специальное тестирование интерфейсов.