Text
                    Тестирование
черного ящика

Технологии функционального
тестирования программного
обеспечения и систем



Е орис Бейзер

^ППТЕР

Boris Beizer BLACK-BOX TESTING Techniques for Functional Teslmg of Software and Systems Wiley John Wiley & Sons, Inc. New York Chichester Brisbane Toronto Singapore
Борис Бейзер Тестирование черного ящика Технологии функционального тестирования программного обеспечения и систем ПИТЕР* Москва Санкт-Петербург Нижний Новгород Воронеж Новосибирск • Ростов-на-Дону • Екатеринбург Самара Киев • Харьков Минск 2004
ББК 32.973-018-07 УДК 681.3.06 Б 41 Бейзер Б. Б 41 Тестирование черного ящика. Технологии функционального тестирования программного обеспечения и систем. — СПб.: (1итер, 2004 — 318 с.: ил. ISBN 5-94723-698-2 Книга доктора Бейзора «Тестирование черного ящика» давно была признана классическим трудом в области поведенческого тестирования разнообразных систем. В ней глубоко рассматриваются основные вопросы тестирования программного обеспечения, позволяющие отыскать максимум ошибок при минимуме временных затрат. Чрезвычайно подробно излагаются основные методики тестирования, покрывающие все спектры аспекгов разработки программных систем. Методичность и широта изложения делают эту книгу незаменимым помощником при проверке правильности функционирования программных решений. Книга предназначена для тестировщиков программного обеспечения и программистов, стремящихся повысить качество своей работы. ББК 32.973-018-07 УДК G81.3.06 Права на издание получены по соглашению с издательством Wiley Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав Информация, содержащаяся в данной книге, получена из источников, рассматриваемых издательством как надежные Тем не менее, имея в виду возможные человеческие или технические ошибки издательство не может гарантировать абсолютную точность и полноту приводимых сведений и не несет ответственности за возможные ошибки связанные с использованием книги ISBN 0-471-12094-4 (англ ) ISBN 5-94723-698-2 © by John Wiley & Sons, Inc © Перевод на русский язык, ЗАО Издательский дом «Питер», 2004 © Издание на русском языке, оформление ЗАО Издательский дом «Питер». 2004
Содержание Введение...............................................................12 Пропущенные модели.....................................................14 1. Общие положения...............................................14 2. Маерс. «Искусство тестирования программ»......................14 3. Логические модели.............................................16 4. Языковые модели...............................................16 RE ADME.DOC...........................................................18 Зачем нужен Readme.doc?...........................................18 План книги........................................................18 Структура главы...................................................20 Бланки налоговой декларации и ссылки на них.......................22 Что должен знать читатель.........................................22 Не только программное обеспечение.................................23 Использование алфавитного указателя...............................23 Ссылки............................................................23 Контроль качества.................................................24 Благодарности.....................................................24 Отказ от ответственности..........................................25 От издательства...................................................25 Глава 1 • Введение.....................................................26 1.1. Обзор........................................................26 1.2. Основные термины.............................................26 1.3. О тестировании...............................................31 1.3.1. Тестировщик и программист............................31 1.3.2. Почему мы тестируем программное обеспечение?.........31 1.3.3. Стратегия тестирования...............................33 1.3.4. Парадокс пестицида...................................34 1.3.5. Природа и причины ошибок.............................34
1.3.6. Когда надо остановиться...............................36 1.3.7. Тестирование черного ящика — это еще не все...........36 1.3.8. Тестирование — это еще не все.........................37 1.4. Процесс разработки программного обеспечения...................39 1.4.1. То, что на самом деле важно............................39 1.4.2. Десять и одна заповедь управления процессом............40 1.5. Вопросы для самопроверки......................................43 Глава 2 • Графы и отношения..............................................44 2.1. Обзор.........................................................44 2.2. Основные термины..............................................44 2.3. Примеры графов, используемых в тестировании...................50 2.3.1. Обзор.................................................50 2.3.2. Модель потока транзакций (Главе 6)....................51 2.3.3. Модель меню с конечным число!" состояний (Глава 9)....51 2.3.4. Модель потока данных (Глава 5)........................51 2.3.5. Модель времени выполнения.............................52 2.4. Отношения.....................................................52 2.4.1. Обзор.................................................52 2.4.2. Транзитивные и метранзитивные отношения . ............52 2.4.3. Симметричные и несимметричные отношения...............53 2.4.4. Рефлексивные и нерефлексивные отношения...............54 2.4.5. Классы эквивалентности и разбиения....................55 2.4.6. Альтернатива графам...................................55 2.5. Основополагающие принципы тестирования........................57 2.5.1. Обзор.................................................57 2.5.2. Построение графа......................................58 2.5.3. Определение отношений.................................58 2.5.4. Проверка узлов........................................59 2.5.5. Проверка связей.......................................59 2.5.6. Тестирование весов....................................60 2.5.7. Тестирование циклов...................................60 2.6. Резюме........................................................61 2.7. Вопросы для самопроверки......................................62 Глава 3 • Тестирование потока управления.................................63 3.1. Обзор.........................................................63 3.2. Основные термины..............................................63 3.3. Отношения и модель............................................65 3.3.1. Основы ...............................................65 3.3.2. Моделирование составных предикатов....................69 3.4. Методика......................................................71 3.4.1. Основы................................................71 3.4.2. Построение модели.....................................72
3.4.3. Выбор путей тестирования.............................77 3.4.4. Активизация..........................................83 3.4.5. Предсказание итогов..................................88 3.4.6. Проверка соответствия пути...........................90 3.5. Рассмотрение приложения......................................91 3.5.1. Индикаторы приложений................................91 3.5.2. Предположения об ошибках.............................91 3.5.3. Ограничения и предостережения........................92 3.5.4. Автоматизация и инструментальные средства............92 3.6. Резюме.......................................................93 3.7. Вопросы для самопроверки.....................................94 Глава 4 • Тестирование циклов..........................................97 4.1. Обзор........................................................97 4.2. Основные термины.............................................97 4.3. Отношения и модель...........................................99 4.3.1. Основы...............................................99 4.3.2. Детерминированные циклы........................... 100 4.3.3. Недетерминированные циклы...........................101 4.3.4. Вложенные циклы.....................................103 4.3.5. Неструктурированные (ужасные) циклы.................103 4.4. Методы......................................................104 4.4.1. Критические тестовые значения.......................104 4.4.2. Детерминированные циклы.............................106 4.4.3. Недетерминированные циклы...........................107 4.4.4. Вложенные циклы.....................................109 4.5. Рассмотрение приложения.....................................110 4.5.1. Индикаторы приложений...............................110 4.5.2. Предположения об ошибках............................110 4.5.3. Ограничения и предостережения.......................110 4.5.4. Автоматизация и инструментальные средства...........110 4.6. Резюме......................................................111 4.7. Вопросы для самопроверки....................................111 Глава 5 • Тестирование потоков данных..................................ИЗ 5.1. Обзор.......................................................113 5.2. Основные термины............................................113 5.3. Отношения и модель..........................................118 5.3.1. Основы..............................................118 5.3.2. Аналогии с графами потока данных.................119 5.3.3. Короткие замечания и упрощенные методы..............125 5.3.4. Упорядочение, совмещение потока управления и потока данных, циклы....................................127 5.4. Методы......................................................131
5.4.1. Основы ...............................................131 5.4.2. Иерархия покрытия.....................................133 5.4.3. Построение модели.....................................136 5.4.4. Выбор основного порожденного подграфа.................138 5.4.5. Итоговый пример.......................................143 5.4.6. Активизация...........................................145 5.4.7. Предсказание итогов...................................147 5.4.8. Проверка соответствия пути............................147 5.5. Анализ приложений............................................148 5.5.1. Виды приложений.......................................148 5.5.2. Предположения об ошибках..............................148 5.5.3. Ограничения и предостережения.........................149 5.5.4. Автоматизация и инструментальные средства.............149 5.6. Резюме.......................................................150 5.7. Вопросы для самопроверки.....................................150 Глава 6*1 вотирование потоков транзакций................................152 6.1. Обзор........................................................152 6.2. Основные термины.............................................152 6.3. Отношения и модель...........................................155 6.3.1. Основы................................................155 6.3.2. Маркировки............................................156 6.3.3. Очереди...............................................157 6.3.4. Слияние и поглощение..................................158 6.3.5. Циклы.................................................159 6.3.G. Фокус и иерархические модели..........................159 6.4. Методика.....................................................160 6.4.1. Основы................................................160 6.4.2. Иерархия покрытия.....................................163 6.4.3. Построение модели.....................................164 6.4.4. Выбор путей и/или порожденных подграфов тестирования .... 165 6.4.5. Тестирование синхронизации............................168 6.4.6. Тестирование очереди..................................169 6.4.7. Активизация...........................................171 6.4.8. Предсказание итогов...................................172 6.4.9. Проверка соответствия пути............................173 6.5. Рассмотрение приложений......................................174 6.5.1. Индикаторы приложений.................................174 6.5.2. Предположения об ошибках..............................174 6.5.3. Ограничения и предостережения.........................174 6.5.4. Автоматизация и инструментальные средства.............175 6.6. Резюме.......................................................176 6.7. Вопросы для самопроверки.....................................176
Глава 7 • Тестирование доменов..........................................179 7.1. Обзор........................................................179 7.2. Основные термины.............................................179 7.3. Отношения и модель...........................................184 7.3.1. Обоснование...........................................184 7.3.2. Основы................................................186 7.3.3. Анализ неопределенностей и противоречий...............191 7.3.4. Нелинейные домены.....................................193 7.4. Методы.......................................................194 7.4.1. Основы................................................194 7.4.2. Недостатки комбинирования экстремальных точек.........195 7.4.3. Слабая стратегия 1x1, одномерное пространство.........197 7.4.4. Слабая стратегия 1x1, пространство с размерностью два и выше...................................................199 7.4.5. Вырожденный случай....................................201 7.4.6. Стратегии более высокого порядка для пространства с размерностью два и более..................................201 7 АЛ. Сильное тестирование доменов . ....................206 7.5. Рассмотрение приложений......................................207 7.5.1. Индикаторы приложений.................................207 7.5.2. Предположения об ошибках..............................208 7.5.3. Ограничения и предостережения.........................208 7.5.4. Автоматизация й инструментальные средства.............209 7.6. Резюме.......................................................209 7.7. Вопросы для самопроверки.....................................209 Глава 8 • Синтаксическое тестирование...................................211 8.1. Обзор........................................................211 8.2. Основные термины.............................................211 8.3. Отношения и модель...........................................216 8.3.1. Основы................................................216 8.3.2. Комментарий о трудозатратах...........................219 8.4. Методы.......................................................219 8.4.1. Основы................................................219 8.4.2. Иерархия покрытия.....................................221 8.4.3. Чистое синтаксическое тестирование....................221 8.4.4. Грязное синтаксическое тестирование...................223 8.4.5. Предсказание итога....................................228 8.4.6. Хорошие и плохие разновидности тестирования...........228 8.5. Рассмотрение приложений......................................230 8.5.1. Индикаторы приложений.................................230 8.5.2. Предположения об ошибках..............................232 8.5.3. Ограничения и предостережения.........................233 8.5.4. Автоматизация и инструментальные средства.............234
8.6. Резюме.......................................................234 8.7. Вопросы для самопроверки.....................................234 Глава 9 • Тестирование систем с конечным числом состояний...............237 9.1. Обзор........................................................237 9.2. Основные термины.............................................237 9.3. Отношения и модель...........................................242 9.3.1. Основы...............................................242 9.3.2. Модели Мили и модели Мура............................245 9.3.3. Таблицы переходов....................................246 9.3.4. Вложенные автоматы...................................248 9.3.5. Улучшаем модель......................................249 9.4. Методы.......................................................250 9.4.1. Основы...............................................250 9.4.2. Что необходимо проверить.............................252 9.4.3. Проверка лишних состояний............................254 9.4.4. Иерархия покрытия....................................256 9.4.5. Активизация и предсказание итога.....................258 9.4.6. Подсчет состояний....................................258 9.4.7. Средства поддержки и тестируемость...................259 9.5. Рассмотрение приложений......................................260 9.5.1. Индикаторы приложений................................260 9.5.2. Предположения об ошибках . . ........................261 9.5.3. Ограничения и предостережения........................262 9.5.4. Автоматизация и инструментальные средства............263 9.6. Резюме.......................................................264 9.7. Вопросы для самопроверки.....................................264 Глава 10 • Инструментальные средства и автоматизация....................268 10.1. Обзор.......................................................268 10.2. Основные термины............................................268 10.3. Обязательная автоматизация..................................269 10.4. Базовый пакет инструментов..................................272 10.4.1. Основы..............................................272 10.4.2. Инструменты для покрытия............................273 10.4.3. Автоматизация проведения тестирования...............275 10.4.4. Автоматизация проектирования тестов.................277 10.4.5. Рекомендации по выбору производителя инструментов тестирования.................................................278 10.4.6. Не обманывайте сами себя............................279 10.5. Будущее тестирования........................................279 10.5.1. Основы..............................................279 10.5.2. Зачем и почему я не верю в тестирование.............279
10.5.3. Зачем и почему я не верю в независимое тестирование.280 10.5.4. Будущее тестирования ...............................281 10.6. Вопросы для самопроверки..............................282 Приложение А...........................................................283 Список литературы......................................................299 Алфавитный указатель...................................................314
Введение Для кого написана эта книга? Для разработчиков и тестировщиков программно- го обеспечения. Говоря «тестировщик», я имею в виду людей, которые регулярно или в настоящее время тестируют программы, написанные другими людьми. Под «разработчиками» я подразумеваю людей, разрабатывающих программное обес- печение, но, сейчас занимающихся тестированием своих программ. Тестирование, выполняемое и теми и другими, слабо зависит от внешнего вида программы, оно подразумевает, что вы ставите себя на место пользователя и проверяете, что про- грамма ведет себя так, как должна, вне зависимости от способа ее создания. Это и означает тестирование методом черного ящика. Большинству начинающих тестировщиков, особенно если они нигде этому не учились, приходится самим исследовать тестирование методом черного ящи- ка (иначе его называют поведенческим тестированием или функциональным тес- тированием). Без соответствующей подготовки они изучают по книгам эвристи- ческие версии методов, для которых могут существовать специально написанные коммерческие инструментальные средства. Для таких пользователей в данной книге содержатся основные сведения о надежных и доступных методах поведен- ческого тестирования. На освещение этих вопросов меня подталкивали производители инструментов для тестирования, поскольку они создают сложные продукты, основанные отчас- ти на технологиях, описанных в этой книге, но пользователи не владеют методами, реализованными в их инструментах. Возникает замкнутый круг. Тестировщики с большой неохотой вкладывают деньги в обучение новым методам. Особенно те из них, кто полагается на автоматику, хотя для этого уже существуют специаль- ные коммерческие инструменты. Производители не могут инвестировать средс- тва в разработку инструментов, включающих такие методы, пока не появятся тес- тировщики, владеющие этими методами. Эта книга призвана помочь разрушить замкнутый круг. Прочитайте ее, затем отправляйтесь к производителю, чьими ин- струментальными средствами вы пользуетесь, и требуйте включить в них методы
из соответствующей главы. А если я отправлю производителям данные о прода- жах этой книги, это будет для них явным признаком того, что риск обоснован, так как на самом деле существует рынок спроса на их инструменты и большое число опытных тестировщиков, понимающих особенности методов и принципов, на ко- торых они основаны. Я должен сказать, чего в этой книге нет. Она не вмещает в себя огромный объем литературы по тестированию, так, например, она не заменяет мою книгу «Методы тестирования программного обеспечения», 2-е издание ([SST2 — BEIZ90]). SST2 — это всеобъемлющий (550 страниц) обзор литературы по тестированию. Эта книга предназначена для максимально широкой аудитории — от разработчи- ков, до тестировщиков, исследователей, студентов и аспирантов. Настоящая кни- га слишком мала, чтобы выполнить такую работу. Здесь не рассматриваются воп- росы дизайна программ, в отличие от SST2, где они присутствуют почти в каждой главе. SST2 охватывает как структурное тестирование, так и поведенческое тести- рование. Здесь же обсуждается лишь тестирование поведения. Эта книга также не может заменить работы «Тестирование программного обеспечения и обеспечение качества» [BEIZ84] или моей следующей книги «Интеграция и тестирование сис- тем», над которой сейчас идет работа [BEIZ96], Там речь идет о системном тести- ровании и тестировании интеграции систем, а обсуждаемые методы используются для создания тестов интеграции и тестов систем. В книге «Интеграция и тестиро- вание систем» я буду считать, что вы прочитали эту книгу и знакомы с соответс- твующими методами. В данной книге вы не встретите теоретических аспектов тестирования. Я не буду доказывать теорем и упомяну лишь о немногих. Эта книга для практиков. Тем не менее, вы можете быть уверены, что все, что имеет под собой прочную те- оретическую базу, основано на этих теоремах. Как следствие моей попытки со- ответствовать теоретическим нюансам, временами текст, а особенно определе- ния, могут показаться излишне формальными, очень похожими друг от друга и на первый взгляд не имеющими прямого отношения к вопросу. Если такое слу- чится, то будьте уверены, что в дополнительной литературе вы найдете ответы на свои вопросы, поскольку эта книга полностью согласуется с литературой по дан- ной тематике. Еще несколько вещей, которые я не собираюсь здесь делать. Я не собира- юсь тратить ваше время, рассуждая, насколько важны тестирование и качество. Если вы еще этого не знаете, то вам полезнее будет подумать над этим вопро- сом. Также я не стану распространяться об обеспечении качества, менеджмен- те, организации, политике, финансах, культуре, становлении программистского эго, о том, кто должен тестировать программное обеспечение, надо ли тестиро- вать программное обеспечение, нужны ли нам законы, обеспечивающие качест- во программного обеспечения, открытых системах, свободно распространяемых программных средствах, проблеме наркотиков или моральном облике современ- ной молодежи. Все это очень интересно. Я оставляю эти темы вам для обсужде- ния и исследования. Если же вы хотите освоить методы поведенческого тести- рования с минимумом предварительных условий и хлопот, тогда, я надеюсь, эта книга вас не разочарует.
Пропущенные модели 1. Общие положения Этот раздел для читателей, знакомых с литературой по тестированию, в особеннос- ти читателей книги Глена Маерса «Искусство тестирования программ» [MYER79]; читателей, которые могут быть озадачены, если я не расскажу о нескольких мето- дах поведенческого тестирования. В первую очередь о логических моделях. Сначала я поставил себе цель уложиться в 175-страничную книгу. Этот объем вполне подходит для прочтения за один семестр. Одновременно планировалось, что эта книга заменит устаревший шедевр Масрса. Маерс уложился в 191 страницу. Когда я начал писать, для меня стало очевидно, что примеры занимают больше мес- та, чем я предполагал. Я добавил некоторые новые технические требования, и это оз- начало, что мне придется включить больше материала, чтобы книга была самодоста- точной. Цель «175 страниц» была недостижима, и, тем не менее, мне приходилось постоянно себя ограничивать, сокращая материал. Мои технические семинары служили обратной связью для определения тем, кото- рые наиболее интересны людям. Я проводил их свыше 200 раз на протяжении 10 лет для тысяч тестировщиков. Участники семинара заполняли опросный лист, в котором спрашивалось, какие методы, по их мнению, могут быть полезны для них сразу же, а какие могут пригодиться в будущем (скажем через 3-5 лет). Я поддерживаю связь с бывшими студентами и организациями-заказчиками, чтобы определить, какие методы они используют при тестировании. Эта обратная связь лежит в основе данной книги. 2. Маерс. «Искусство тестирования программ» Книга «Искусство тестирования программ» освещает вопросы тестирования так, как их понимали в 1979 году. С тех пор прошло более двух десятилетий, техноло-
гии тестирования развивались, и читатели не будут удивлены, обнаружив, что тех- ника тестирования тоже изменилась. С одной стороны, сегодня мы знаем о тести- ровании гораздо больше. С другой стороны, создание подобного обзора потребует сейчас не одной, а целых семи книг: «Инспектирование», «Методы тестирования», «Тестирование интеграции», «Системное тестирование», «Теория тестирования», «Методы отладки», «Организация тестирования» и «Менеджмент». Моя задача существенно уже — введение в технику тестирования. Вот современное описание пяти методов, обсуждаемых Маерсом. 1. Тестирование путем покрытия логики. То, что Маерс называл «тестирова- нием путем покрытия логики», в настоящее время называется тестировани- ем потока управления (глава 3). Поскольку в данной книге рассматривают- ся не структурные методы (белого ящика), а лишь поведенческие методы (черного ящика), я остановлюсь лишь на поведенческом тестировании по- тока управления. 2. Разбиение по эквивалентности. Все методы тестирования, описанные в этой книге, основаны на идее разбиения набора всех возможных входных данных на классы эквивалентности (глава 3). Это означает, что все они от- носятся к методам тестирования путем разбиения. Маерс настоятельно со- ветовал читателям исследовать код и спецификации, а затем на их осно- ве осуществлять разбиение входных данных на эквивалентные классы для тестирования программы. Он также предложил для этого несколько слож- ных эвристических правил. Это выливается ь создание специальных мето- дов для каждой конкретной программы. Принцип, конечно, правильный и абсолютно корректный, но на практике тестировщики испытывают трудно- сти при определении этих смутных (хоть и плодотворных) классов эквива- лентности. Я расскажу вам об уже готовых методах разбиения на классы эк- вивалентности (или методах тестирования), что облегчает их практическое использование. 3. Анализ граничных значений. Рассуждения Маерса об анализе граничных значений являются частью более общей и более мощной методологии тес- тирования доменов (глава 7). Некоторые аспекты анализа граничных зна- чений в применении к циклам будут обсуждаться в главе 4. 4. Причинно-следственные диаграммы [ELME73, MYER79]. Более подроб- ное обсуждение вопроса, почему причинно-следственные диаграммы и свя- занные с ними методы не включены в данную книгу, приводится в разделе 3 «Логические модели». Такие методы трудны в практическом использова- нии потенциальными тестировщиками, не обладающими необходимыми знаниями, такими как булева алгебра или теория переключательных схем. Остранд [OSTR88] замечательно отозвался об этой технике: «Переводя данные спецификации в причинно-следственные диаграммы, тестировщи- ки замещают одно сложное представление другим». 5. Предположение об ошибках. При выборе метода тестирования мы делаем ставку на определенный тип ошибок, который ожидаем обнаружить, так
как предположение о типе ошибок присутствует в любом методе. Поэтому предположение об ошибках — это не какой то метод тестирования, но атри- бут любого из методов. Предположение об ошибках, основанное на статис- тике ошибок программистов, — вполне здравая идея (посмотрите, однако, «Парадокс пестицида» в главе 1). Сегодня мы имеем подобные статистики и, опираясь на них, выбираем определенный метод тестирования. Существует также и формальная теория тестирования, основанного на ошибках, но она не вошла в эту книгу [HOWD89, MORE90]. 3. Логические модели Логические модели включают в себя причинно-следственные диаграммы [ELME73, MYER79], модели таблиц решений [BEIZ90, GOOD75] и множество других ва- риантов, использующихся в качестве частей различных методологий дизайна [BF.ND85, WEYU94B], Это замечательные методы, однако для их разбора пот- ребуется слишком много места. К примеру, логические модели занимают в книге «Методы тестирования программного обеспечения» 42 страницы. В данной книге из-за более современных предпосылок и примеров черновик состоял из 75 стра- ниц. Это еще две дополнительные большие (даже слишком большие) главы, что сделает курс слишком большим для одного семестра. Мне трудно объяснить логические модели без привлечения булевой алгебры, а ее нет смысла учить, если вы не владеете диаграммами Карно—Вейча [BEIZ90], поскольку булева алгебра почти не используется без этого важного инструмента. Я обратил внимание, что слушатели разделяются на две категории. Те, кто знаком с булевой алгеброй и картами Карно, способны овладеть этими методами само- стоятельно, например, с помощью STT2. Те же, у кого нет таких знаний, не могут изучить их за четыре часа, которые я посвящаю этой теме. В итоге тестирование на основе логики всегда находится на последних местах в списке предпочтений моих студентов и спонсоров. И я частенько вообще выбрасываю эту тему из моих семинаров. Было бы неплохо, чтобы курс по тестированию был не единственным. Вспо- могательный курс, для начальных или старших курсов, когда студенты уже владе- ют необходимыми знаниями, мог бы включать в себя логические модели и другие модели, здесь не представленные. 4. Языковые модели Существует большое число моделей на основе специальных языков для разра- ботки тестов и связанных с ними инструментальных средств. Хорошим приме- ром может служить метод разбиения по категориям Остранда [LAYC92, OSTR88] и «Т» Постона [POST94]. Другие методы того же типа изложены в [BALC89, BELF76, DAVI88, КЕММ85, RICH89]. Все эти методы основаны на языке опре- деления теста. Языки отличаются степенью формальности и выразительной си- лой, простираясь от самых элементарных до строгих полнофункциональных язы-
ков. При помощи таких языков тестировщики определяют требуемое поведение программ. Языковый процессор проверяет это определение на неоднозначности и противоречия. Другой процессор автоматически генерирует тестовые варианты (положительные и отрицательные), соответствующие данному определению при помощи большого числа формальных и эвристических методов тестирования. Что же плохого в таком способе? Ничего. Я люблю его. Я верю, что рано или поздно тесты будут преимущественно создаваться такими вот инструментами. Однако подобные средства сложны, и их нельзя понять по-настоящему без пони- мания методов тестирования, на которых строятся генераторы тестов. Прочтя эту книгу, вы узнаете об этих методах. Другая проблема является фундаментальной для любого языка программи- рования. Один из наиболее важных выводов, которые я сделал, наблюдая почти четыре десятилетия за развитием программного обеспечения, заключается в том, что нельзя ставить все на какой-то язык программирования, пока он популярен. Да и после потери популярности не стоит зацикливаться на нем. Люди предре- кали кончину языка COBOL десятилетиями, но он, подобно бессмертному вам- пиру, все еще с нами. Кто мог предположить, что С вытеснит языки ассембле- ра, почти полностью FORTRAN и даже COBOL? Что случилось с языками PL/1 и Algol? Достоинства языков программирования слабо связаны с их популярно- стью. Будущее языков тестирования еще в большей степени непредсказуемо из-за относительно небольшого круга пользователей. Я надеюсь, что со временем один или два таких языка и связанные с ними генераторы тестов станут общепризнан- ными средствами тестирования. Тогда и наступит время написать о них, может быть, в рамках дополнительного курса.
Readme.doc Зачем нужен Readme.doc? Смогу ли я добиться большего успеха, чем производители фирменного программ- ного обеспечения, попытавшись убедить вас прочесть этот раздел, прежде чем вы перейдете к следующим главам? Данный раздел — это инструкция по поль- зованию данной книгой. Я ничем не отличаюсь от вас. Когда мне в руки попада- ет новый пакет программ, я запускаю то, что мне интересно, начинаю с ним ма- нипулировать и неизбежно захожу в тупик. Тогда я возвращаюсь назад и читаю Readme.doc, для того чтобы узнать, что же я сделал не так. Поэтому, если вы чита- ете этот раздел, это значит, что вы попытались прочесть главу о методах, которые, на ваш взгляд, подходят для вашей задачи, но безуспешно. Итак, давайте прочтем это прямо сейчас. План книги Эта книга имеет свою генеральную линию. В глазе 1 подготавливается почва для дальнейшего изложения и говорится о моем видении вашей ситуации, или, ины- ми словами, обстоятельств, в которых происходит ваше тестирование. Для неко- торых из вас эти обстоятельства могут показаться идеалистическими, но на самом деле они реальны и в той или иной форме присутствуют во множестве органи- заций-разработчиков программного обеспечения, и это то, к чему вам надо стре- миться. Сравнивая вашу ситуацию с главой 1, вы поймете, где вы находитесь и в каком направлении вам надо двигаться. Для тех, кто ориентируется в терминах, мои стандарты — пятый уровень зрелости SEI (по шкале Института программно- го обеспечения) и, кроме того, немного из [SCAC94], Глава 2 необходима для понимания глав 3, 4, 5, 6, 8 и 9, глава 4 — для глав 5, 6 и 8. Вы — в большинстве своем тестировщики-практики, и я не буду осуждать вас,
если вы пропустите главу, которая покажется вам чересчур абстрактной или не имеющей отношения к вашей конкретной задаче. Прошу за это прощения. Глава 2 очень важна. Если вы не разберетесь в ней, то последующие главы могут быть не- понятны. В лучшем случае вы не сможете извлечь из них столько пользы, как если бы вы прочитали эту главу. Глава 2 подобна подпрограмме с нужной информацией. Вместо того чтобы снова и снова повторять основные принципы в различных контекстах для каждой главы, я опишу идеи тестирования один раз в абстрактной форме и буду ссылать- ся на них в дальнейшем. Если вы разберетесь в абстрактных понятиях главы 2, то в последующих главах объяснение методов будет занимать всего несколько стра- ниц. Это сделает книгу короче и дешевле, а КПД усвоения выше. В главах с 3 по 9 описываются конкретные методы. В каждой главе — один ме- тод и его производные. Я постарался сделать эти главы как можно более независи- мыми друг от друга. Переварив главу 2, вы сможете читать остальные главы прак- тически в любом порядке. Данная диаграмма показывает, какой материал должен быть предварительно освоен перед прочтением той или иной главы. Сплошные линии означают, что вы должны разобраться в главе, находящейся в начале стрелки, для того чтобы понять главу, па которую стрелка указывает. Прерывистые линии означают, что предварительная глава содержит определения, которые будут использоваться в последующей главе, но любом случае вы сможете понять материал без вниматель- ного изучения предварительной главы. Прочтение главы 1 — желательно, но не- обязательно для понимания следующих глав. Последняя глава включает в себя
определения из остальных глАв, и поэтому требование к предваряющим главам нежесткое. В последней главе рассказывается об инструментальных средствах и авто- матизации. И хотя методы, описываемые в этой книге, могут использоваться и безо всякой автоматизации, такое их использование будет крайне неэффективно. Я надеюсь, что вы простите мне, что я не вдаюсь в подробности при обсуждении инструментальных средств. Я не собирался делать здесь полный обзор послед- них коммерческих инструментов. Такую информацию можно найти в [DAIC93], [GRAH93], [SQET94] и других подобных периодических изданиях. Ситуация ме- няется слишком быстро, для того чтобы имело смысл печатать подобную инфор- мацию в книге. Структура главы Главы с 3 по 9, составляющие ядро данной книги, имеют сходную структуру, хотя порядок может меняться от главы к главе. Обзор. Содержание главы в общих словах без использования терминов, вводи- мых в данной главе. Словарь внешних терминов. Технические термины, определение которых от- сутствует в данной книге, но которые вы должны знать. Англоговорящего читате- ля может удивить, что сюда включено так много основных компьютерных терми- нов. Около половины содержимого словаря внешних терминов хорошо знакомо не только профессионалу в области программного обеспечения, но и студенту. Включая сюда основные термины, я преследовал цель помочь моим многочислен- ным читателям, для которых английский язык не является родным. Я также на- деюсь, что эти термины ощутимо облегчат перевод книги. Некоторые из внешних терминов не принципиальны для понимания книги, поскольку используются лишь в одной из нескольких иллюстраций идеи или в несущественном коммента- рии. Не слишком расстраивайтесь, если вы не понимаете термины, используемые в иллюстрациях, поскольку они играют вспомогательную роль в освоении мето- дов тестирования. Все такие термины есть в алфавитном указателе, и вы можете посмотреть их применение в контексте изложения, чтобы понять, действительно ли они вам нужны для понимания темы. Словарь внутренних терминов. Термины, определяемые в предыдущей главе. Словарь новых определений. Определения, используемые в главе. Новые опре- деления выделяются курсивом. Определение будет выделено курсивом еще раз, если оно дополняется или уточняется. Определения приводятся в логической по- следовательности, где каждое следующее определение зависит от предыдущего; их надо читать в предложенном порядке. Внимательно читайте новые определе- ния и не двигайтесь дальше, пока их не поняли. Конфликт словарей. Иногда вы будете находить один и тот же термин во внеш- нем и внутреннем словарях, а также в словаре новых определений. Когда термин появляется одновременно во внешнем и внутреннем словарях, это значит, что если вы знали его и раньше, то у вас не будет проблем с пониманием главы, одна-
Структура главы 21 ко в данном контексте определение будет более строгим, чем то, которое вы зна- ли. Аналогично, если термин возникает во внутреннем словаре и в словаре новых определений, то в данной главе он либо уточняется, либо дополняется (переопре- деляется). Термины могут выделяться в тексте курсивом (это значит, что вы, скорее всего, с ними не знакомы), при этом их определение может отсутствовать, и они не бу- дут включены в словарь новых определений. Это означает, что этот термин ссы- лается на что-то, что будет определено позже. Я старался избегать таких ссылок и использовал их, только если чувствовал, что это принесет пользу. Вы, возмож- но, захотите заглянуть в соответствующую главу и просмотреть определение, но в любом случае можете не беспокоиться: на изучение данной главы никак не влияет понимание подобных ссылок. Модель. Модель, на которой основан метод. Она включает то, что мы принима- ем во внимание в поведении программы, что игнорируем и как мы представляем себе это поведение. Предположение об ошибках. Любой метод тестирования основан на предполо- жении относительно программного продукта, дизайна, пользователя, типа оши- бок и возможных проявлений этих ошибок. Этот раздел поможет вам определить эффективность метода в вашем случае. Тип приложений. Обсуждение, для каких приложений данный метод, скорее всего, будет эффективен. Метод. Метод, что он собой представляет, как он работает и почему он работает. Примеры. Примеры и решения технических задач — от необходимых требо- ваний до готовых тестов. Там, где это было возможно, я использовал в качестве примеров декларацию о доходах внутренней налоговой службы США. Я выбрал бланки декларации на подоходный налог, поскольку они едины для всех, содер- жат большое количество нетривиальной логики; они подходят для иллюстраций большинства методов черного ящика; несмотря на то, что мы затрачиваем огром- ные усилия, чтобы заполнить бланк декларации и разобраться в этих непостижи- мых формах, они, тем не менее, представляют собой вполне законченные специ- фикации и свободны от ошибок; и, наконец, их должен знать каждый. Предостережения и ограничения. Что данный метод может, чего не может и ошибки какого типа он пропустит. Автоматизация и инструментальные средства. Комментарии по поводу ав- томатической генерации совокупности тестовых данных и инструментальных средств, построенных на этом методе. Резюме. Краткое содержание главы с использованием новой терминологии. При сравнении обзора и резюме становиться понятно, какие новые концепции были рассмотрены в этой главе. Тест и упражнения. Упражнения и вопросы по итогам главы. Не прилагая уси- лий, вы не станете хорошо тестировать. Также вам надо знать терминологию, вве- денную в этой главе, если она встречается в последующих главах. Станьте сами себе ОТК. Проверьте себя. Бланки налоговой декларации являются подходящими объектами для тестирования. Проверьте сделанное, протестировав готовый пакет налоговых документов. Можете считать, что все правила налоговой службы в нем
i соблюдены. В том числе они проверяют, чтобы все обязательные для заполнения графы были заполнены. Если вы вводите некое значение, очевидно выходящее за указанные рамки, программа должна определить это и предупредить вас. Я дол- жен извиниться за то, что использовал налоговые декларации за 1994 год, по если они изменятся (а это неизбежно случится), вы приобретете полезный навык в об- новлении средств тестирования. Если вы в данный момент не являетесь студентом, то с помощью этого упраж- нения вы дополнительно попрактикуетесь в заполнении налоговой декларации. Если же вы студент и никогда не заполняли декларацию, самое время научиться этому. Не осуждайте меня за сложность формы, обратитесь лучше с этим вопро- сом к своим сенаторам и конгрессменам. Кроме того, реальные проблемы, с кото- рыми вам придется столкнуться при тестировании программ, будут гораздо более трудными. Бланки налоговой декларации и ссылки на них Там, где это было возможно, я иллюстрировал методы на примере формы 1040 де- кларации о доходах внутренней налоговой службы США и дополнений к ней за 1994 год. Копии форм, использующихся в этой книге, содержатся в приложении А. Эти формы определяют структуры, которые мы и будем тестировать. Я рассчиты- ваю, что каждый раз, разбирая пример, вы будете сверяться с соответствующей копией формы. Я ссылаюсь на различные строки в бланке декларации как «1040 строка 23» Если отдельно не оговаривается, отсутствие названия формы (например, бланк С) означает, что ссылка относится к форме 1040. Также для создания полезных при- меров мы можем добавлять отсутствующие в настоящей форме «строки» в нашу модель. Так, например, вместо одной строки 34 могут возникнуть строки 34.1,34.2 и т. д. Что должен знать читатель Эта книга для людей, обладающих определенными знаниями и опытом. Одного из нижеследующего будет вполне достаточно: один год (или больше) обучения по университетской программе в области компьютерных наук или программной инженерии, два года среднего специального образования в области компьютер- ных наук или разработки программного обеспечения, интенсивный годовой курс обучения в сертифицированном коммерческом центре обработки данных или, что равнозначно, полный курс обучения по направлению «Программное обеспе- чение» в системе военного образования США, три или больше лет работы про- граммистом. Занимаетесь ли вы программированием на данный момент — неваж- но. Важно, чтобы вы знали основные принципы программирования и обладали практическим навыком. Читателям с опытом прикладного тестирования, но без опыта программирования будет сложнее. Им придется потрудиться, чтобы понять и научиться применять главу 2. В словаре внешних терминов для каждой главы
приводится лексика, которую вам надо знать для освоения метода. Большинство людей склонно недооценивать собственные знания. Если вы понимаете термино- логию главы, этого достаточно для ее изучения. Не только программное обеспечение Исходя из вышесказанного, может показаться, что эта книга адресована только раз- работчикам программного обеспечения и тестировщикам. Это не так. Требования к читателю достаточно скромны и являются общими при обучении науке, бизне- су, инженерному делу или бухгалтерии. «Тестирование методом черного ящика» означает, что нас не интересует, чтб выступает в роли программно-подобного про- цесса. Кроме, разумеется, программ, это могут быть химические реакции, физика электромеханических систем, таинственный ход мыслей юриста, когда он пишет налоговые законы. Все эти системы надо тестировать. Все методы, представлен- ные в данной книге, можно применить для тестирования процессов, далеких от программирования. Если вы биохимик и хотите оптимизировать тестирование ре- акций, которые используете в анализе крови, эта книга будет вам полезна, пос- кольку маловероятно, что существует книга о тестировании химических реакций в крови. Или представьте, что наши законодатели и Конгресс захотят применить формальный анализ и методы тестирования к абсурдным налоговым законам (особенно касающимся укрывания налогов), которые они разрабатывают. Тогда они смогут использовать эту книгу, хотя вряд ли это произойдет. Использование алфавитного указателя Алфавитный указатель предоставляет всю информацию о термине, а также содер- жит раздел ссылок. Если в ссылке приводятся номера страниц, то это значит, что в данной работе на указанных страницах содержится информация по соответству- ющей теме. Вам это будет ясно из названия издания или из комментария, следу- ющего за названием. Ссылки Исследователи вряд ли найдут в ссылках что-нибудь интересное для себя. Ссылки здесь приводятся для того, чтобы читатель мог узнать больше о теме, иногда озна- комиться с противоположной точкой зрения или удачными примерами приложе- ний, которые он мог бы использовать как средство борьбы за внедрение данного метода в свою организацию. Я ограничил библиографию работ, которые, хотя и содержат дополнительную информацию, но не являются существенными. Также я не стал включать в список ссылок множество прекрасных работ, особенно теоре- тических исследований, не относящихся к теме данной книги. Ссылки обозначаются согласно требованиям АСМ (ассоциация вычислитель- ной техники). Первые четыре символа из имени автора, затем год публикации, и в
конце заглавная буква, начиная с «А», если это не единственная работа автора за тот год. Так, например, [BEIZ90] — книга Бейзера, опубликованная в 1990 году, а [BEIZ91C] — третья его книга в 1991 году. Часто приводится резюме или корот- кий обзор, если тема не понятна из названия. Контроль качества Контроль качества — это ваша задача. Я ожидаю ваших комментариев, а также ва- ших замечаний об ошибках и недочетах, чтобы исправить их в следующих изда- ниях. Технологии позволяют сделать это очень просто. Пришлите мне факс или e-mail по адресам, приведенным ниже. Пожалуйста, сообщите следующую инфор- мацию о себе: Ваше имя, место работы (компания, университет, государственное учреждение) Ваша должность Почтовый адрес Номер телефона, факса, e-mail Название книги, издание Номер страницы и комментарии или исправления Если вы используете факс, вы можете сделать копию страницы и написать ком- ментарий прямо на ней. В публикациях используются номера, эквивалентные номеру версии и релиза. «Номер версии» — это то же самое, что и «номер издания», это всегда указывается в заголовке. Например, «Методы тестирования программ», издание 2-е. Пожалуйста, посылайте ваши замечания: Борису Бейзеру Факс: 215-88G-0144, три параллельных факса, отвечают на первый звонок E-mail: BBEIZER@MCIMAIL.COM Благодарности Я написал эту книгу по настоянию Боба Постена из Programming Environments Inc при поддержке Джинджера Хостона-Ладлэма из Frontier Technologies, Эдварда Миллера из Software Research Associates, Билла Перри из Quality Assurance Institute, Ричарда Бендера из Bender Associates и еще такого огромного числа кол- лег по академии, что перечислить их не представляется возможным. В написании этой книги есть вклад и других людей: коллег по цеху, моих читателей, моих сту- дентов, клиентов, приходящих на консультации, однако уже трудно сказать, кто из них и что предлагал. Вряд ли кто-нибудь из этих людей догадываются, что они являются соавторами этой книги, поскольку их участие в ее написании было по большей части неосознанным. Мотивация, сознательная или нет — тоже цен- ный вклад. Я также хочу поблагодарить тех, кто откликнулся на мою просьбу по Интернету о помощи в выборе темы. И, наконец, я благодарен Ли Уайту за полез- ную и обоснованную критику главы 7.
От издательства 25 Отказ от ответственности Там, где было возможно в этой книге, я использовал в качестве примеров декла- рации о доходах внутренней налоговой службы США. Они использовались для иллюстрации проблем тестирования и не годятся для предоставления реальной информации, например как заполнять налоговую декларацию или как интерпре- тировать код внутренней налоговой службы США. Я по своему усмотрению со- кращал или изменял формы, если это мне было надо в педагогических целях. Не используйте формы из этой книги для каких-либо реальных целей, связанных с налогами. Не представляйте эти формы, их копии или материал в них в налоговую службу. Я не несу ответственности за любое их использование, кроме как в качес- тве учебных пособий. Несмотря на вышесказанное, бланки декларации, их запутанность и инструк- ции к ним совпадают с формами внутренней налоговой службы США. Мои кол- леги-неамериканцы говорят мне, что налоговые законы сложны во всем мире. Я за это не отвечаю. Законы и формы на самом деле дают нам нечто, за что можно быть благодарным. Если вы в состоянии заполнить налоговую декларацию в своей стране, то вы можете решить любую задачу тестирования, например тестирование программы контроля ядерного реактора. От издательства Ваши замечания, предложения и вопросы отправляйте по адресу электронной почты comp@piter.com (издательство «Питер», компьютерная редакция). Мы будем рады узнать ваше мнение! Подробную информацию о наших книгах вы найдете на веб-сайте издательства http://www.piter.com.
Введение 1.1. Обзор В этой главе вводится терминология, использующаяся в тестировании, и рассматри- вается тестирование как элемент процесса разработки программного обеспечения. 1.2. Основные термины В тестировании программного обеспечения существует вполне устоявшийся сло- варь. Определения, данные в этой книге, широко используются, изучите их. Вы на- верняка ошибетесь, если будете употреблять их в узком, а не в широком смысле. Внешние термины: совокупность, алгоритм, анализ, бета-тестирование, ветв- ление, побочный продукт, вызов, вызываемый, вызывающий, параметры запро- са, код, кодирование, связь, сравнивать, компилируемый сегмент, компилятор, за- вершенный, сложность, вычисление, последовательный, управление, аварийная ситуация, данные, база данных, порча данных, целост ность данных, отлаживать, задержка, проектирование, детерминированный, среда разработки, стадия разра- ботки, диск, документ, выполнять, эксперимент, файл, блок-схема, формальный анализ, функция, глобальные данные, аппаратные средства, гипотеза, реализу- емый, независимое тестирование, инспектирование, инсталляция, взаимодействие, нажатие клавиши, ключевое слово, библиотека, макрос, сопровождение, управ- ление, отображение, сообщение, метрика, модель, модуль, многозадачный, мно- гопользовательский, команда объектной программы, объектно-ориентированное программирование, взаимно однозначное отображение, операционная система, выходные данные, производительность, процесс разработки программного обес- печения, обработка, программа, часть программы, оператор программы, програм- мируемый, программист, программирование, протокол, качество, обеспечение ка- чества, RAM (оперативная память), случайный, диапазон, надежность, ресурсы,
многократно используемый, экран, защита, набор, последовательность, совмест- но используемые данные, имитатор, программное обеспечение, логика програм- мы, исходный код, область, оператор, статистический, память, управление памя- тью, подпрограмма, подсистема, инструмент тестирования, таблица, пропускная способность, истинностное значение, пользователь, значение, переменная. Объект. Общий термин, включающий в себя данные и программное обеспечение. Состояние. Набор всех значений всех объектов в данном множестве объектов в произвольный момент времени. Смысл термина «состояние» зависит от того, определяет ли он набор объектов и/или их состояний: например, состояние эле- мента, состояние системы, состояние объекта, начальное состояние. Начальное состояние. Состояние объекта перед началом теста. Конечное состояние. Состояние объекта после прохождения теста. Ввод. Любой способ, при помощи которого данные могут быть доставлены объ- екту. Примеры: сохраненные данные, генерируемые данные, нажатие клавиши, сообщение. Наблюдаемый. Любое видимое и ожидаемое изменение состояния объекта, или отсутствие изменений в состоянии объекта, если это изменение не ожидалось. Примеры: новый экран, неправильные выходные данные, нсизменившийся экран. Итог. Наблюдаемый результат теста. Примеры: изменившийся объект данных, сообщение, новый экран, изменение состояния, неизменный объект, отсутствие сообщения, пустой экран. В тестировании мы рассматриваем итог, а не вывод. Это не семантическое противоречие. То, что экран не изменился, очевидно, является итогом, по не выводом. Если вы полагаете, что все тесты должны иметь вывод, то вы упустите множество полезных тестов. Все тесты, однако, должны иметь итог. Оракул. Любые средства, используемые для предсказания итога теста [HOWD86]. Проектирование теста. Процесс определения объекта, начального состояния и ввода, а также прогноз итога теста и/или конечного состояния для данного объ- екта, начального состояния или ввода. Тестирование. Проектирование, отладка и выполнение тестов. Подтест. Наименьшая составная часть теста, включающая в себя объект, на- чальное состояние, ввод и прогнозируемый итог. Тест. Последовательность одного или более подтестов, выполняемых после- довательно. Итог и/или конечное состояние одного подтеста является вводом и/ или начальным состоянием для другого. Термин «тест» обобщает, включает в себя подтесты, тесты как таковые и тестовые комплекты. Тестовый комплект. Совокупность одного или более тестов, ориентированных на один объект с общей задачей и базой данных и используемых, как правило, сов- местно. Опровергаемый. Оператор является опровергаемым, если вы можете поставить эксперимент, который либо подтвердит, либо опровергнет его истинность. Требования. То, что объект должен выполнять и/или характеристики, кото- рыми он должен обладать. Выбор требований относительно произволен, но они должны быть непротиворечивы, разумно полны, реализуемы и, что самое важное, опровергаемы.
Характеристика. Желательное поведение объекта; вычисление или оценка, проводимые объектом. Требования представляют собой совокупность характе- ристик. Вариант. Характеристики, представляющие собой совокупность вариантов. Спецификация. Ясное, как правило, неполное определение требований. В ка- честве спецификаций могут использоваться документы, список характеристик, прототип, тестовый комплект. Спецификации обычно незакончены, поскольку многие требования часто бывают очевидны. Например: «программа не должна уничтожать или портить данные». Самая большая ошибка, которую может допус- тить тестировщик, — это предположить, что в спецификациях представлены все требования. Проверка соответствия (валидация). Оценка объекта с целью продемон- стрировать, что он удовлетворяет требованиям. Тестирование — это не единствен- ный метод проверки соответствия, но в данной книге рассматривается только он [WALL94], Искаженностъ'. Оценка объекта с целью продемонстрировать, что он не удов- летворяет требованиям. Критерии соответствия (валидации). Средства для демонстрации того, вы- полняются или нет требования. Например, прямое сравнение с предсказанны- ми значениями, сравнение в пределах определенных областей значений, наблюда- емая последовательность событий. Сравнение итогов. Предсказанный и фактический итоги теста сравниваются по определенным критериям соответствия. Сценарий теста. Документ, программа или объект, которые для каждого тес- та и подтеста в тестовом комплекте определяют тестируемый объект, требование (обычно условие), начальное состояние, вводы, ожидаемый итог и критерии соот- ветствия. Симптом (отказ IEEE94). Наблюдаемое аномальное поведение любого объек- та (не обязательного тестируемого), такое как несоответствие требованиям или возникновение незапланированных явлений. Ошибка (сбой IEEE94). Просчет в проектировании, ведущий к возникновению симптомов у какого-либо объекта (тестируемого и не только) при прохождении этим объектом определенного теста. Тест считается пройденным, если при корректно заданных критериях соответ- ствия после его прохождения фактический итог совпадает с предсказанным и от- сутствуют симптомы. Тест считается не пройденным, если после его прохождения фактический итог не совпадает с предсказанным и/или присутствуют симптомы. Причиной этого может быть использование неверного объекта, неверный ввод, неверный прогно- зируемый итог, неверное начальное состояние, неверные критерии соответствия, некорректное применение этих критериев, ошибка при проектировании теста, 1 Автор использует свою собственную, оригинальную терминологию. Отдавая дань классику, от- метим, что более распространены следующие термины: верификация — проверка того, что программа правильно реализует определенную функцию; валидация — проверка того, что программа соответству- ет требованиям заказчика. — Примеч. научи, ред.
ошибка в выполнении теста, ошибка в процессе проверки соответствия и даже, ка- ким бы это не могло показаться странным, ошибка в тестируемом объекте. Протестирован. Объект считается (успешно) протестированным, если вы- полнены все запланированные тесты, без появления симптомов, это означает, что все тесты были пройдены. Если не указано обратное, «протестирован» означает — успешно протестирован. Свободен от ошибок. Мы говорим, что объект «свободен от ошибок», если мы считаем, что вероятность появления у него симптомов или возникновения спрово- цированных им симптомов у других используемых объектов достаточно мала, что- бы гарантировать успешное использование этого объекта. Идея абсолютной «сво- боды от ошибок» является неопровергаемой, а значит, не может быть требованием. Случайная корректность. Успешное прохождение всех тестов еще не означает, что объект свободен от ошибок. Несмотря на то, что фактический итог совпадает с предсказанным, в программе могут быть ошибки, поскольку совпадение итогов мо- жет быть случайным. Например, если программа должна вычислять у :=хг, но ошиб- ка в программировании приводит к тому, что вычисляется у:=2х, а входное значе- ние х в тесте оказывается равным 2, то итог будет равен у-4, несмотря на ошибку. Про тестируемую таким образом программу говорят, что она случайно корректна. Слепота (сокрытие, утаивание). Для любого метода тестирования (за исклю- чением тестирования всех возможных вводов и начальных состояний) существу- ет определенный тип ошибок, к которым он слеп. Например, множество методов слепо к случайной корректности. Модуль. Наименьший элемент, подлежащий тестированию. Этот элемент (обычно) является продукцией одного программиста и представляет собой на- именьший компилируемый сегмент программы, такой как подпрограмма. Модуль как объект тестирования обычно не включает в себя подпрограммы, вызываемые им функции, фиксированные таблицы и так далее. Тестирование модуля. В тестировании модулей принято, что вызываемые под- программы и вызовы функций считаются компонентами языка (например, клю- чевыми словами). Вызываемые и вызывающие компоненты считаются либо ра- ботающими корректно, либо заменяются имитаторами. Тестирование модулей обычно является задачей их разработчиков. Ошибка модуля. Ошибка, которая, скорее всего, будет выявлена при грамотном тестировании модуля. Модуль является компонентом. Компонент представляет собой совокупность одного или более компонентов, которая может тестироваться как единое целое. Например, модуль, подпрограмма, функция, макрос, программа и подпрограм- мы, которые она вызывает, связанные процедуры и целые системы программного обеспечения. Интерфейс между компонентами — любые средства, при помощи которых данные могут передаваться или совместно использоваться. Это может быть вы- зов подпрограммы, общий объект данных, глобальные данные, физический интер- фейс, сообщение. Тестирование интеграции-. Тесты, направленные на проверку взаимодейс- твия и совместимости компонентов, успешно прошедших свои тесты. То есть
компоненты А и В, которые прошли тесты компонентов, объединяются в новый компонент С = (А, В). Тестирование интеграции направлено на проверку согла- сованности получившейся совокупности. Интересующее нас поведение совокуп- ности обычно исследуется с помощью интерфейса между компонентами. Ошибка интеграции. Ошибка, которая, скорее всего, будет выявлена при гра- мотном тестировании интеграции. Интеграция. Процесс тестирования интеграции, отладки интерфейса и ис- правления ошибок интеграции. Интеграция может изменить характер поведения и тем самым привнести новые ошибки. Интеграция обычно производится созда- телем компонентов, если за связываемые компоненты ответственен один человек. Зачастую ее независимо выполняет отдельный интегратор, если в создании ком- понентов участвовало несколько человек. Тестирование компонента. Тестирование компонента отличается от тестирова- ния модуля тем, что оно включает в себя тестирование вызываемых компонентов и объектов данных. Например, тестирование процедуры совместно с вызываемыми ею подпрограммами, тестирование процедуры и фиксированной таблицы данных. Разумное тестирование компонента подразумевает предварительную успешную ин- теграцию подчиненных компонентов и модулей и тестирование интеграции этих компонентов. В отличие от тестирования компонентов при тестировании модулей модуль когда-нибудь составит единое целое с относящимися к нему компонентами. Ошибка компонента. Ошибка, которая, скорее всего, будет выявлена при тес- тировании компонента. Системы программного обеспечения Совокупность компонентов, такая, что определенные требования могут быть проверены, даже если некоторые компонен- ты отсутствуют или не подвергались тестированию. Тестирование системы производится для проверки поведения системы, которая не может быть выполнена путем тестирования модулей, компонентов или тестиро- вания интеграции. Например, тестирование, производительности, инсталляции, це- лостности данных, управления памятью, безопасности, надежности. В идеале тести- рование системы предполагает, что все узлы были заранее успешно интегрированы. Тестирование системы часто осуществляется независимыми тестировщиками. Ошибка производительности. Ошибка, главным симптомом которой является неудовлетворительная или заниженная производительность (например, низкая пропускная способность или увеличение задержки). Ошибка безопасности. Ошибка, увеличивающая риск несанкционированного проникновения в систему, что позволит просматривать или изменять файлы, не обладая соответствующими правами. Ошибка потери ресурсов. Ошибка, ведущая к потере динамически размеща- емых ресурсов, таких как оперативная память или место на диске. Системная ошибка. Ошибка, вероятность обнаружения которой путем тести- рования модулей, компонентов или интеграции мала. Ошибка, проявляющаяся в поведении не отдельных компонентов, но системы целиком. Например, ошибка производительности, ошибка безопасности, ошибка потери ресурсов. Модули, подпрограммы, программы, подсистемы. Приблизительные названия компонентов, расположенные по мере явного возрастания их размера.
Окружение. Совокупность аппаратных, программных средств и данных, в ко- торых и посредством которых компоненты создаются, тестируются и использу- ются. Сюда входят (но этим перечень не ограничивается) вызывающие и вызыва- емые компоненты, операционная система, аппаратные средства, компилятор, ваши средства тестирования (разумеется) и прочее, что может влиять на работу компонентов или зависеть от нее. 1.3. О тестировании 1.3.1. Тестировщик и программист Повсюду в этой книге мы будем упоминать и противопоставлять друг другу «тес- тировщиков» и «программистов» так, как будто они являются разными людьми. Такое разделение может привести вас к мысли, что тестирование методом черно- го ящика предназначено только для независимых тестировщиков, но не для про- граммистов. Другим ошибочным мнением является то, что я сторонник идеи, что тестирование и программирование должны выполняться различными людьми, (то есть должно проводиться независимое тестирование). Я хочу предотвратить и/или скорректировать такие ошибочные взгляды. Говоря образно, программист должен косить две шляпы — шляпу програм- миста и шляпу тестировщика. Когда он выполняет тестирование, он должен на- деть шляпу тестировщика и думать как тестировщик. Вот что представляет собой «тестировщик», для которого я пишу эту книгу. Итак, тестировщик может быть, а может и не быть тем же самым человеком, который пишет программы. Так как способ мышления при программировании и способ мышления при тестировании сильно отличаются, хорошая идея — просто рассказать о двух ролях, как будто бы их играют различные люди. Способ мышления в программировании известен давно и существует много книг по этой теме, поэтому не стоит специально на этом останавливаться. Способ мышления, применяемый при тестировании, возник от- носительно недавно, и именно поэтому эти способы сильно различаются. Методы тестирования, затрагиваемые здесь, предназначены как для независимых тести- ровщиков, так и для тех программистов, которые в данный момент тестируют свое или чье-либо программное обеспечение. 1.3.2. Почему мы тестируем программное обеспечение? Для проведения тестирования программного обеспечения есть несколько весо- мых причин. 1. Обеспечение программистов информацией, которую они смогут использо- вать для предотвращения ошибок. 2. Обеспечение менеджеров информацией, которая необходима им для разум- ной оценки риска при использовании объекта. 3. Создание объекта, максимально свободного от ошибок.
4. Создание проекта, поддающегося тестированию, то есть проекта, который можно легко проверить на соответствие, на искаженность и который будет легко сопровождать. 5. Проверка искаженное™ объекта с помощью как сформулированных, так и не сформулированных требований [MYER79]. Это еще называют «взло- мом программного обеспечения». 6. Проверить соответствие объекта (убедиться в его действенности), то есть показать, что он работает правильно. Информация, необходимая для выполнения пункта 2, определяется степенью, до которой объект действует правильно (то есть количеством подтестов, пройден- ных и не пройденных), и некоторыми рамками, в пределах которых объект не мо- жет быть искажен. То есть пределом, до которого объект не взломан, и пределом, до которого он работает. Тот предел, до которого объект считается свободным от ошибок, является также границей, до которой он соответствует требованиям и не искажен. Таким образом, у нас есть три основных задачи: хорошее проектирова- ние, искаженность, проверка соответствия Все, что пишут люди, содержит ошибки. Проведенное тестирование чего-либо не является эквивалентом утверждения, что это что-то свободно от ошибок. Программист не может думать обо всем — в особенности обо всех возможных вза- имодействиях между различными характеристиками и между различными час- тями программы. Мы пытаемся взломать программу, так как только такой путь обеспечит нас уверенностью в том, что продукт готов к использованию. Другая задача тестирования — это накопление информации для менеджмента. При наличии необходимой информации и достаточного количества тестов мы мо- жем с достаточной уверенностью утверждать, что программа готова к использо- ванию. В конечном счете это как раз то, за что платят тестировщикам, — помощь в создании полезной программы. Наивысшая цель тестирования — это обеспечение качества: накопление ин- формации, которая, вернувшись к программисту, поможет избежать ему прошлых ошибок и улучшить качество программного обеспечения в будущем. Грязный тест (или негативный тест)-, тест, первичной целью которого явля- ется проверка искаженное™; то есть тест, предназначенный для того, чтобы взло- мать программу. Чистый тест (или позитивный тест): тест, первичной целью которого явля- ется проверка соответствия; то есть тест, предназначенный для того, чтобы проде- монстрировать корректную работу программы. Тест является действенным, если в результате его выполнения выявляются симптомы существующих ошибок. В спецификациях обычно указываются только те требования, которые должны быть проверены на соответствие (то есть на то, что объект должен делать), и не со- держатся требования, которые должны быть проверены на искаженность (то есть на то, что объект не должен делать). Так как количество действий, которые объ- ект должен выполнять, конечно, а количество действий, которые объект не дол- жен выполнять, не ограничено, из общих соображений можно предположить, что
грязных тестов должно быть существенно больше, чем чистых. Так оно и есть на самом деле. В продуманных тестовых комплектах число грязных тестов относится к числу чистых как 4 : 1 или 5:1. 1.3.3. Стратегия тестирования Стратегия тестирования, или методы тестирования — это систематические ме- тоды, используемые для отбора и/или создания тестов, которые должны быть включены в тестовый комплект. Это могут быть случайные вводы, тест, направ- ленный на проверку моих подозрений, тест, направленный на проверку ваших подозрений, тест, направленный на проверку соответствия требованиям, тест, направленный на проверку искаженное™; тесты, который мы выполняли пос- ледний раз, тесты, которые отличаются от тестов, которые мы выполняли послед- ний раз. Мы выбираем стратегию, такую, что существуют правила, по которым мы можем определить, удовлетворяет данный тест стратегии или не удовлетворяет. В принципе, стратегия должна быть программируемой. Стратегия является эффективной, если тесты, включенные в нес, с большой ве- роятностью обнаружат ошибки тестируемого объекта. Эффективность стратегии зависит от комбинации природы тестов и природы ошибок, на поиск которых эти тесты направлены. Как на войне и в бизнесе, здесь существуют эффективные и не- эффективные стратегии. Более того, так как объект изменяется с целью исправле- ния ошибок и увеличения его возможностей, типы ошибок, находимые у объекта, меняются со временем, и, следовательно, меняется эффективность стратегии. В то время как теоретически возможно, что стратегия по отношению к специфическим объектам совершенствуется во времени, на самом деле эффективность большин- ства стратегий со временем убывает. Стратегия поведенческого теста основана на технических требованиях. Например: тест всех характеристик, упомянутых в спецификации, выполнение всех грязных тестов, вытекающих из требований. Тестирование, выполняемое с помощью стратегии поведенческого теста, называется поведенческим тестиро- ванием. Поведенческое тестирование называется также тестированием черного ящика. Для поведенческого тестирования также используется термин функцио- нальное тестирование'. При поведенческом тестировании (в принципе, но не на практике) не обязательно знать, как объект сконструирован. Тема этой книги — поведенческое тестирование (тестирование черного ящика). Стратегия структурного теста определяется структурой тестируемого объек- та [BASI87, BEIZ90, NTAF88, OSTR96], Например: выполнение каждого операто- ра по меньшей мере один раз, выполнение каждой ветви но меньшей мере один раз, тестирование использования всех объектов данных, выполнение каждой команды 1 Термин «функциональное тестирование» обычно используется в литературе, но на практике предпочитается термин «тестирование черного ящика». Лучший и более старый термин, существу- ющий в компьютерных науках, — «поведенческое тестирование». Проблемы с «функциональным тестированием» связаны с тем, что этот термин используется для обозначения некоторой стратегии тестирования, используемой, например, для тестирования математических функций. В этой книге три термина «функциональное тестирование», «тестирование черного ящика», «поведенческое тестирова- ние» подменяют друг друга с доминированием термина «поведенческое -юстирование».
объектной программы, полученной при компиляции. Тестирование, выполненное с помощью стратегии структурного теста, называется также тестированием про- зрачного ящика или тестированием белого ящика. Стратегия структурного теста требует полного доступа к структуре объекта — то есть к исходному коду. Эта кни- га только поверхностно затрагивает методы структурного тестирования. Стратегия гибридного теста является комбинацией поведенческой и структур- ной стратегий [CLAR76, RICH81], Поведенческая, структурная и гибридная стра- тегии не противоречат друг другу, и ни про одну из них нельзя сказать, что она луч- ше других. Модули и низкоуровневые компоненты часто тестируются с помощью структурной стратегии. Большие компоненты и системы в основном тестируются с помощью поведенческой стратегии. Гибридная стратегия полезна на всех уровнях. Не существует лучшей стратегии, так как полезность стратегии зависит от приро- ды тестируемого объекта, природы ошибок объекта и уровня ваших знаний. 1.3.4. Парадокс пестицида1 Большинство из нас предпочитают доделать дело до конца. Знать, что работа вы- полнена, выполнена правильно, и в подходящее время взять следующее задание. Тестирование программного обеспечения на это не похоже. Если вы хорошо сделали работу по выявлению ошибок и если люди из отдела обеспечения качества хорошо выполнили работу по передаче ваших исследований обратно программистам, то они, скорее всего, не повторят прошлых ошибок Хороший программист, если у него есть время и необходимые ресурсы, обычно изучает проблемы, выявленные тестировщи- ками (или им самим), обобщает идеи и затем исследует свое программное обеспече- ние на предмет выявления и исправления в нем таких же или подобных ошибок. Все методы тестирования имеют встроенные допущения о природе ошибок. Каждый метод тестирования нацелен на определенный набор ошибок. Если про- граммист реагирует на результаты тестирования и информацию об ошибках со- кращением и удалением этих ошибок, из этого следует, что его программа улуч- шается, а эффективность предыдущих тестов постепенно уменьшается. То есть ваш тест устаревает и вам приходится изучать, создавать и использовать новые тесты, основанные на новых методах отслеживания новых ошибок. 1.3.5. Природа и причины ошибок Обратитесь к [BEIZ90] и [ANSI94] для подробного обсуждения ошибок и катего- рий ошибок. Главная причина, почему я использую термин «ошибка», а не офици- альный термин «дефект», это то, что «дефект» подразумевает, что кто-то должен нести за него ответственность. Предполагается недостаток добросовестности про- граммиста, леность или некомпетентность. Ошибки, сделанные компетентным программистом, работающим на современном программном обеспечении, в соот- ' Это называется «парадокс пестицида» по аналогии с явлением в сельском хозяйстве, когда ли- чинки долгоносика, приспособившись к яду. вынуждали нас создавать все более мощный яд, который приводил к возникновению все более устойчивых к этому яду личинок, или искать принципиально иное решение.
ветствующей среде разработки программного обеспечения, не являются дефекта- ми (надеюсь, вы не будете обвинять нас в излишней мягкости). В хорошем, продуманном программном обеспечении источником ошибок яв- ляются сложность и ограниченная способность людей к борьбе со сложностью, а не тупость. Чем лучше программный процесс, тем менее вероятно, что ошибки, ко- торые сохраняются в течение поведенческого тестирования, являются ошибками конкретных программистов. Большинство ошибок, которые мы находим при помо- щи поведенческого тестирования в хорошо разработанном, качественном програм- мном обеспечении, являются следствием непредсказуемого взаимодействия между компонентами или между объектами, или результатом непредсказуемых побочных эффектов, вызываемых совершенно невинными, на первый взгляд, процессами. Если ошибки, найденные в результате поведенческого тестирования, — про- стые и их легко распределить по категориям, это говорит о том, что неудовлетво- рителен технологический процесс, а не программист. Мы принимаем на веру, что программист хорбшо обучен, обладает надлежащими инструментами и компетен- тен1. Это называется «гипотезой компетентного программиста». Так как человек, который проводит поведенческое тестирование, не обязательно является тем же самым человеком, который пишет программное обеспечение, важно иметь в виду эту гипотезу, считая, что человеческие недостатки и неприязнь не вторгаются в процесс программирования. Полезны три широкие категории ошибок: ошибки модулей/компонентов, ошибки интеграции и системные ошибки, названные так в соответствии с той фа - зой разработки, в которой, вероятнее всего, могут быть найдены ошибки. Ошибки модулей/компонентов найти и избежать легче всего. Когда мы тести- руем систему и тест выявляет ошибку, мы не можем сказать, что явилось этому причиной, — ошибка модуля, ошибка интеграции или системная ошибка. Это мы узнаем только после того, как ошибка будет устранена. Так как системное тести- рование требует гораздо больших ресурсов, чем тестирование модулей/компо- нентов, выявление ошибок модулей, оставшихся к моменту начала системного тестирования, представляет собой напрасную трату сил. Таким образом, задачей тестирования модулей/компонентов является сокращение числа ошибок, кото- рые переходят в последующие стадии процесса. Ошибки интеграции более трудны для выявления и предотвращения, так как они возникают при взаимодействии .между компонентами, которые являются корректными сами по себе. Взаимодействие компонентов подчиняется законам комбинаторики, что означает, что их число растет как п2 (как квадрат числа задей- ствованных компонентов) или даже хуже (например, как п! — факториал числа компонентов). Цель тестирования интеграции — убедиться в том, что когда мы переходим к системному тестированию, некорректных взаимодействий между компонентами совсем не осталось или осталось мало. Системное тестирование — это качественно новый уровень тестирования. Даже если все особенности были проверены при тестировании модулей/компо- 1 Если некомпетентный программист нс может стат ь компетентным, избавьтесь от него. Если про- цесс содержит ошибки, исправьте его. Ни от кого нельзя ожидать продуктивности без надлежащих инструментов.
нентов или при тестировании интеграции, нам следует включить поведенческое тестирование как составную часть системного тестирования. При тестировании модулей/компонентов или интеграции то, что мы тестируем, имеет детерминиро- ванное поведение. При системном тестировании у нас, однако, возникают допол- нительные трудности, связанные с многозадачностью. Следовательно, порядок, в котором будут возникать те или иные ситуации, уже не может быть с уверенно- стью предсказан. Такая неопределенность и проблема синхронизации являются богатой почвой для более сложных ошибок. Основная цель системного тестиро- вания — убедиться в том, что в недетерминированном мире программное обеспе- чение ведет себя так же предсказуемо, как и в детерминированном мире. 1.3.6. Когда надо остановиться Процесс тестирования потенциально бесконечен, как с теоретической, так и с практической точки зрения. Тем не менее, даже зная, что ошибки остались, мы должны завершить тестирование, так как если мы этого не сделаем, все усилия будут напрасны. Если у нас есть большое количество опытных данных, то можно создать статистическую модель, которая даст нам понимание того, насколько рис- кованно прекратить тестирование и предложить протрамму для коммерческого использования [HAML94, MUSA90].Ecnn вы почувствовали некоторую осторож- ность моей формулировки, запомните это, так как обоснованность таких моделей не очевидна и не бесспорна. Тем не менее, прогресс не стоит на месте, и большинс- тво полезных моделей нуждаются в информации, которую мы собираем при тес- тировании, особенно в ходе системного тестирования, и которая является частью данных, используемых для определения момента завершения тестирования. 1.3.7. Тестирование черного ящика — это еще не все Тестирование поведения, это еще далеко не все, что мы должны сделать. Одного тестирования мало. Если мы рассматриваем все тестирование, которое мы можем и должны провести с программой, от начала и до конца, поведенческое тестирова- ние занимает 35-65% от общего времени’. Относительная полезность поведенче- ского тестирования зависит от проекта. Если в проекте все характеристики жес- тко запрограммированы с использованием специальной логики, то структурные методы превалируют. Когда проект основан на использовании общих алгорит- мов, чье специфическое поведение определяется при помощи таблиц данных или параметров вызова, то преобладает поведенческое тестирование. Важность пове- денческого тестирования подобна важности различных методов навигации. Что именно является наиболее важным, зависит от погоды, от близости берега, от того, какими приборами вы располагаете, и так далее. Нам следует прислушаться к мо- 1 В объектно-ориентированном программировании увеличивается важность поведенческого тести- рования. Ясно, что методы поведенческого тестирования будут более важны для создания программ- ного обеспечения при помощи падежной библиотеки многократно используемых объектов, чья вну- тренняя работа и структура сознательно от нас скры i ы; ведь нам, возможно, придется проводить гораз- до больше тестов, для того чтобы быть уверенными в надежности объектов | BERA94, NORT94J.
ему любимому автору Натаниелю Боудичу [BOWD77]: «Мудрый штурман ни- когда не полагается только на один метод». 1.3.8. Тестирование — это еще не все Ошибки, обнаруженные в процессе тестирования, должны нас, с одной стороны, радовать, с другой стороны — огорчать. Радовать, так как это означает, что на одну проблему стало меньше; огорчать, поскольку это указывает на несовершенство на- шего процесса разработки программного обеспечения. Радовать, так как мы узна- ли, как усовершенствовать процесс и предотвратить подобные проблемы в буду- щем. Мы создаем программы около 40 лет, и наиболее важный урок, который мы усвоили, звучит следующим образом: «Делайте это как можно раньше!» Чем раньше ошибки найдены и исправлены, тем дешевле обходится их исправ- ление. Усилия, затрачиваемые до начала проектирования, меньше, чем усилия, за- трачиваемые в течение проектирования. Усилия, затрачиваемые до начала напи- сания кода, меньше, чем усилия, затрачиваемые после написания кода. Усилия, затрачиваемые на тестирование модулей, меньше, чем усилия, затрачиваемые на системное тестирование, которые, в свою очередь, меньше усилий, затрачиваемых после инсталляции программы. Ниже приводится несколько эффективных мето- дик, не связанных с тестированием, приблизительно в том порядке, в котором они должны применяться. Создание прототипа. Прототипом программы является урезанная реализа- ция, которая имитирует то поведение программы, которое необходимо пользова- телю [STAK89], Цель этого — дать нечто осязаемое пользователю, чтобы он мог нам сказать, является ли полезным для него то, что мы создаем, будет ли он это впоследствии покупать. Прототип на самом деле не обязан работать и обычно не работает. Мы создаем программное обеспечение для пользователей. Привлечение их к процессу как можно раньше является эффективным подходом, позволяющим избежать грубых промахов. Анализ требований. Требования задают содержание проектирования [YEHR80], Если требования несовместимы, то проектирование не может быть корректным. Анализ требований означает проверку требований на логическую непротиворечи- вость, тестируемость, легкость реализации. Мы не можем ожидать, что пользова- тель обеспечит нас адекватными требованиями, так как он не умеет этого делать. Мы все были бы похожи на машину, которая, не загрязняя окружающую среду, проезжает 100 километров на литре воды, везет 12 взрослых людей и помещается на стоянке 3 х 2 м. Мы все были бы похожи на «Мерседес» по цене «Запорожца». Нашей целью как создателей программного обеспечения не является сделать не- возможное и удовлетворить все капризы пользователей. Нашей целью является разработка продукта, соответствующего своей цене. Формальный анализ [ANDE79, ВАВЕ94, HANT76, WING94]. Мы не можем тестировать все, да и нет в этом необходимости . Это особенно справедливо в слу- чае поведенческого тестирования. Множество вещей, которые мы не можем на практике протестировать в настоящее время (и вряд ли когда-нибудь сможем), включает в себя все возможные способы взаимодействия характеристик друг с
другом. Тестирование поведения программы при каждом возможном варианте инсталляции, является другой неосуществимой задачей. То же самое относится к взаимодействию между нашим пакетом программ и другими пакетами, проверке защищенности нашей программы, некоторым коммуникационными протоколам и множеству алгоритмов. Всякий раз, когда по ряду причин сложность тестиро- вания увеличивается быстрее, чем сложность самого тестируемого объекта, фор- мальный анализ, возможно, математический, является предпочтительнее тести- рования. Мы, однако, нуждаемся в тестировании, чтобы убедиться, что сам наш анализ в должной мере свободен от ошибок1. Проектирование. Хороший проект имеет мало ошибок и легко тестируется. Намного легче спроектировать что-то, что не может быть протестировано, чем что-то, поддающееся тестированию. Намного легче спроектировать что-то, что со- вершенно невозможно сопровождать, чем спроектировать что-то, что возможно. Самые грамотные требования сводятся на нет непродуманными проектами, про- верить которые невозможно при помощи конечного числа тестов. Формальное инспектирование [FAGA76, GILB93, WEIN90] является пер- вичным методом предотвращения ошибок, и это неоднократно подтверждалось. Процесс разработки программного обеспечения, который не включает в себя фор- мальное инспектирование, очевидно дефектен, и устранение ошибок в нем намно- го больше зависит от тестирования. Самотестирование. Тестирование, выполняемое самими программистами, го- раздо более эффективно, чем тестирование, выполняемое кем-то еще. То же самое относится к тестированию группой, производящей данное программное обеспе- чение. Аналогично тестирование в организации, разрабатывавшей программное обеспечение, эффективнее, чем внешнее тестирование (то есть бета-тестирование) того же самого программного обеспечения. Это не отвергает идеи, что независи- мое тестирование может быть действенно, так как эффективность — не единствен- ный критерий, определяющий, кому и какое тестирование проводить. Если независимый тестировщик повторяет тест, ранее выполненный разработ- чиком, или просто выполняет тестирование, которое следовало бы выполнить во время разработки, в этом случае независимое тестирование совсем не приносит никакой информации, фактически не имеет смысла. Такое тестирование (незави- симое повторение тестов разработчика) может быть полезно, только если разра- ботчик некомпетентен или предумышленно делает не все корректно. А это проти- воречит нашей гипотезе о компетентности программиста. Цель независимого тестирования — обеспечить различные ракурсы, следова- тельно, различные тесты; более того, проводить эти тесты в среде с более широкими возможностями (и поэтому более сложной и дорогой), чем это доступно разработ- чику. Цель самотестирования — удалить те ошибки, которые могут быть найдены 1 Все, что мы делаем в процессе разработки программного обеспечения, подвержено ошибкам. Формальное (то есть математическое) доказательство корректности алгоритма точно так же уяз- вимо для ошибок, как любой другой процесс, выполняемый человеком. Убедиться в этом легко: до- статочно вспомнить о количестве статей в математических журналах, озаглавленных: «Контрпример к теореме...».
посредством малых затрат в простейшей детерминированной среде путем тестиро- вания модулей/компонентов или низкоуровневого системного тестирования. Инструменты. Мы считаем исходные синтаксические ошибки кода просто по- мехами, так как у нас есть инструменты (компиляторы), которые находят такие ошибки гораздо лучше, чем мы сами. В наших языках программирования и ком- пиляторах к настоящему времени появились совершенные детекторы ошибок, ав- томатизировавшие то, что когда-то являлось сложной для человека задачей. Если ошибка может быть определена (и/или исправлена) автоматически, это должно быть сделано. Не пытайтесь отключать автоматизацию и инструменты, выявля- ющие ошибки. Исключить надо как раз подверженную ошибкам ручную обработ- ку кода, тогда, когда доступна автоматизация. Существует все более увеличиваю- щаяся разница между инструментами, которые в действительности используют программисты и тестировщики, и инструментами, которые разрабатывают для них исследователи. Ликвидируйте этот разрыв! Он стоит того. Это окупится. \ Мы, как тестировщики, должны всегда стремиться к тому, чтобы можно было вообще обойтись без тестирования. Это наша недостижимая цель. Тестирование является контролем качества. Обеспечение качества означает предотвращение ошибок. Всегда выгоднее предотвратить ошибки, чем их потом находить. Но эта цель недостижима, так как история показывает, что автоматизация процесса и предотвращение предыдущих ошибок являются предпосылками к встрече со все более сложными задачами, которые ставят перед нами нужды пользователей. Наш текущий технологический процесс (каким бы несовершенным он ни был) является более совершенным, чем технологический процесс, использовавшийся всего десятилетие назад. Мы уже не программируем так, как это делали десять лет назад, но мы пишем новые программы, несущие в себе все более сложные ошибки. Наши пользователи повышают свои требования к качеству, а, следовательно, рас- тут требования к нашим возможностям и методам тестирования. 1.4. Процесс разработки программного обеспечения 1.4.1. То, что на самом деле важно Наиболее важные моменты, касающиеся разработки программного обеспече- ния, легко перечислить. Нам необходим процесс. Процесс должен быть понятен. Процессу должны следовать. Процесс. Я убежден, что процесс используется в любом случае, поскольку даже хаос в своем роде является процессом. Наличие процесса означает, что существу- ет возможность предсказать, что будет происходить с программным продуктом на следующем шаге. Такая предсказуемость возникает, когда появляется потреб- ность в данном продукте, и завершается, когда продукт устаревает. Наличие процесса еще не означает существования детально разработанной для него документации. Ряд наилучших проектов на моей памяти имели крайне огра- ниченный объем документации. И наоборот, когда меня спрашивают о том, что
необходимо иметь, я ссылаюсь на подробно задокументированное описание про- цесса, оставшееся после одного из самых крупных провалов из тех, что мне доводи- лось видеть. Объем формальной документации для конкретного проекта напрямую зависит от размера этого проекта. Документы (если они читаются) — это наиболее эффективный способ донести детали проекта до человека, не разбирающегося в данном процессе и в предпосылках к проекту. Контролировать процесс, а значит обеспечить его качество обычно проще, если шаги в процессе задокументированы. Он понятен. Если процесс непонятен тому, кто должен его понимать, то этому процессу невозможно следовать. Понимания можно добиться, читая документа- цию, если только людям дается время на осознание и суммирование того, что они прочли. Может в этом помочь и видео. Обучение общим методам работы с процес- сами лишено смысла, поскольку портят дело обычно специфические особенности, а не общие закономерности. Вам будет необходимо освоить особенности некото- рого конкретного процесса. Ему следуют. Наличие понятного процесса еще не означает, что ему будут сле- довать. Индикатором того, что в процессе возникли проблемы, служит возник- новение расхождения между формальным процессом (то есть задокументирован- ным процессом) и тем, что фактически делают люди. В таких случаях я встаю на сторону программистов и тестировщиков, идущих своим путем, а не тех умников, которые этот процесс придумали. Если процесс игнорируют, то это, скорее всего, потому, что он не работает, а не потому, что программисты — закостенелые рет- рограды. Большинство людей, хотя и не все, если им указать более эффективный способ сделать что-либо и обеспечить инструментами и навыками, необходимы- ми для работы, будут следовать этому новому пути. Процессом перестают руко- водствоваться в случае, если он ущербен, если существуют преграды для его ис- пользования или если не хватает необходимых ресурсов ( го есть навыка, времени, инструментов). 1.4.2. Десять(16) и одна заповедь управления процессом В таком разделе во множестве разных книг вы можете найти тщательно разрабо- танные наборы блок-схем процедур с таинственным образом обозначенными пря- моугольниками и стрелками различных видов и стилей, входящими в эти прямо- угольники и выходящими из них во всех направлениях. Я не собираюсь здесь этого делать, поскольку усвоил одно еретическое правило: блок-схемы и модели про- цесса ничего не значат. Они ничего не значат, поскольку провал или успех процес- са разработки программного обеспечения никоим образом не определяются мо- делью данного процесса. Культурные, этнические, прикладные и национальные особенности оказывают гораздо большее влияние на процесс, нежели грандиоз- ные теории процессов. Утверждение «Процесс А лучше процесса Б» равносильно утверждению «Японский язык лучше тагальского». Говорить, что рецензирование предварительного проектирования должно предварять кодирование, то же самое, что говорить: «В предложении глаголы должны идти впереди существительных». Специфические особенности языка, а также порядок слов очень важны для гово-
рящего на этом языке, а также для тех, кто занимается переводами с одного языка на другой, но не они определяют способность носителя языка к общению. Итак, мы не будем рассматривать модель водопада [ROYC70] или спиральную модель [ВОЕН86], пошаговую детализацию, нисходящую стратегию, восходящую стратегию и все такое прочее. Ниже приводятся составляющие, которые вам надо искать в любом эффективном процессе, подобно тому, как вы ищете существитель- ные, глаголы и другие части речи в разговорном языке, но без указания, в каком по- рядке они должны быть скомпонованы, чтобы получился осмысленный процесс. Дорожная карта процесса. Необходимо понимать в каждый момент времени, па какой стадии процесса находитесь вы и ваша программа. Если вы предпочита- ете блок-схемы процесса — это очень хорошо, но некоторые люди отдают пред- почтение комментариям и спискам. Грамотная дорожная карта процесса разби- вает процесс на элементарные шаги, которые легко понять и контролировать. Она достаточно детальна, чтобы вы или кто-нибудь другой мог легко сориентиро- ваться в ней, но эта детализация не чрезмерна и не подавляет индивидуальность и творческое начало. Управление процессом. Управление процессом не подразумевает жесткого со- блюдения детально расписанного графика, как не означает оно и тоталитаризма и подавления индивидуальности. Управление процессом подразумевает наличие эффективных механизмов, при помощи которых все участники процесса могут получать информацию, касающуюся улучшения тех частей процесса, в которых они напрямую задействованы. Управление процессом включает в себя обратную связь, обучение и широкий круг возможностей, и направлено на создание атмо- сферы в коллективе, в которой люди будут стремиться улучшить себя, свой про- дукт и мир вокруг. Количественные измерения и метрики. Мы имеем дело с инженерной на- укой, а не с искусством, и потому объективность — требование, необходимое для управления процессом. В инженерной науке количественные измерения являют- ся залогом объективности. В компьютерных науках количественные измерения опираются главным образом на метрики [BERL94, FENT91, GRAD87, GRAD92, MOLL93, ZUSE90, ZUSE94]. Контроль конфигурации так же стар, как Имхотеп, великий строитель пирамид. Он означает, что в любой момент времени мы можем проверить результат нашего труда (программу, требования или, скажем, тестовый комплект) и узнать: кто, что, где, когда, зачем и как. Конфигурация всего, с чем планируется дальше работать, должна контролироваться, а все, что не контролируется, просто не входит в наш продукт. Требования. Что мы создаем? Все в курсе? Все имеют в виду одно и то же? Здесь я настаиваю на документировании, поскольку человеческая память ненадежна. Прослеживаемость требований. Откуда взялись требования? Если, как часто бывает, требования изменяются в процессе разработки программы, на какие дру- гие требования это повлияет? Прослеживаемость означает, что требования нахо- дят свое отражение в компонентах программного обеспечения и наоборот. Однако не требуйте и не ожидайте взаимно однозначного соответствия, так как требова- ния и компоненты не отображаются в стиле «один к одному».
Стратегические тонкости. Для кого разрабатывается данное программное обес- печение? Что ожидают заказчики и пользователи от программы, кроме обычной практичности? Не станет ли эта программа кошмаром для пользователя? Будет ли она вне конкуренции? Улучшит ли она нашу репутацию? Принесет ли она боль- шой доход? Будет ли она самой быстрой? Существуют сотни таких стратегических задач, и руководство определяет относительную важность каждой из них. Без по- добного руководства (желательно заданного в количественной форме) невозмож- но определить цели проектирования или понять, когда эти цели достигнуты. Критерии соответствия требованиям. Как мы узнаем, что продукт удовлетво- ряет требованиям? Как выбрать объективные критерии соответствия требовани- ям так, чтобы они были связаны с каждым требованием по отдельности и со все- ми вместе? Ответственность. Кто и за что отвечает. Критерии завершенности. Как узнать, когда данная часть программного обес- печения (ПО) будет готова к переходу на следующую стадию процесса разработ- ки? Что является реальным, объективным признаком завершенности? Критерий готовности. Как узнать, когда данная часть ПО будет удовлетворять условиям, необходимым для перехода к следующей стадии процесса разработ- ки? Подобное описание вовсе не избыточно. Компонент программы может прой- ти через множество стадий или использоваться множеством других компонентов, каждый из которых имеет свои критерии готовности Как правило, критерий за- вершенности компонента является объединением всех критериев готовности для этого компонента. Анализ. Анализ — это инженерный процесс, при помощи которого проекти- рование «наполняется» требованиями (получает полные требования как вход- ной набор данных). Он может быть полностью интуитивным или полностью фор- мальным. Интуитивный анализ, зачастую действенный, не может, однако, быть с легкостью воспринят другими людьми, и, следовательно, какой-либо формаль- ный, часто математический анализ необходим, даже просто для памяти. Проектирование. Это все, что касается сути дела, не так ли? Проектирование должно предварять программирование или, по крайней мере, проводиться одно- временно с ним. Инженеры, прежде чем строить, занимаются проектированием, поскольку это уменьшает риск. Проектные ошибки — это ошибки на бумаге, и обходятся они гораздо дешевле, нежели сваренная сталь или скомпилированный код. Проверка соответствия проекта. Как нам убедиться в том, что проект будет работать, если мы раньше ничего подобного не разрабатывали? Проверка соот- ветствия проекта — это совсем не то же самое, что проверка соответствия реализа- ции проекта. Мосты рушатся из-за плохих, не прошедших проверки проектов, а не из-за плохих материалов и неквалифицированной рабочей силы. Чем новее про- ект, тем важнее его проверить перед началом конструирования. Проверка соот- ветствия производится с помощью моделей, прототипов и инспектирования про- ектирования. Программирование. Написание кода в соответствии с проектом и тестирова- ние его с целью убедиться, что мы создали именно то, что и собирались создать.
Каменщик проверяет горизонтальность своей кладки с помощью уровня, а про- граммист — с помощью тестов. Интеграция. Единое целое по своим возможностям существенно больше, чем сумма отдельных частей. Только у тривиальных, модельных программ уровень сложности системы эквивалентен сумме уровней сложности ее составляющих. Архитектор тратит не меньше времени на придание зданию законченного вида, чем на продумывание шагов по его возведению. Об интеграции не стоит и гово- рить, если не существует плана интеграции и соответствующих тестов интегра- ции, будь то объединение двух низкоуровневых подпрограмм или нескольких со- тен квазиавтономных систем. Тестирование; Тестирование требуется везде, где работают люди. Тестиро- вание — это основная составляющая самоуважения и гордости за свое мастерс- тво. Механик, который не проверяет результат свой работы микрометром, или негодяй, или дурак. Программист, поиском ошибок которого занимаются впослед- ствии только другие люди, не уважает себя, за исключением, возможно, странной гордости за быстрое клепание огромного количества непроверенных и полных ошибок программ. 1.5. Вопросы для самопроверки Дайте определение следующих терминов: анализ, поведенческое тестирование, тестирование черного ящика, слепота, ошибка, свободный от ошибок, вариант, чистый тест, случайная корректность, комбинаторный, гипотеза о компетентном программисте, компонент, ошибка компонента, тестирование компонента, конт- роль конфигурации, проверка соответствия проекта, грязный тест, эффективная стратегия, эффективный тест, критерии готовности, среда, критерии завершеннос- ти, не пройденный тест, отказ, опровергаемый, искаженность, дефект, характерис- тика, конечное состояние, функциональное тестирование, тестирование прозрач- ного ящика, гибридная стратегия, начальное состояние, ввод, интеграция, ошибка интеграции, тестирование интеграции, интерфейс, отрицательный тест, объект, наблюдаемый, оракул, итог, соответствие итогов, пройденный тест, парадокс пес- тицида, ошибка производительности, положительный тест, управление процес- сом, программирование, прототип, цель тестирования, обеспечение качества, кон- троль качества, требования, анализ требований, прослеживаемость требований, критерий соответствия требованиям, ошибка потери ресурсов, действенный тест, ошибка безопасности, система программного обеспечения, спецификация, состо- яние, структурное тестирование, подтест, симптом, система, системная ошибка, системное тестирование, тест, проектирование теста, сценарий теста, стратегия тестирования, тестовый комплект, тестируемый проект, протестированный, тес- тирование, методы тестирования, модуль, ошибка модуля, тестирование модуля, проверка соответствия, критерий соответствия, тестирование белого ящика.
Графы и отношения 2.1. Обзор Графы рассматриваются как основной концептуальный инструмент тестирования. 2.2. Основные термины Внешние термины: приложение, массив, конец стрелки, начало стрелки, банко- мат, двусторонний, ветвь, ошибка, статистика ошибок, вычисление, CASE, код, дан- ные, означать, DO...WHILE, END, динамическое связывание, время выполнения, выбор- ка, файл, FOR...DO, функция, IF-THEN-ELSE, входное значение, инспектирование, список, цикл, меню, опция, модель, мышь, естественный язык, объектно-ориентированное программирование, путь, платежная ведомость, PRINT, вероятность, шаг обработки, программа, ветвь программы, программное управление, вход программы, выход программы, путь программы, оператор программы, программист, язык програм- мирования, READ, RETURN, экран, программное обеспечение, спецификация, элект- ронная таблица, оператор, метка оператора, ограничение по памяти, линейный оператор, подпрограмма, таблица, шаблон, инспектирование теста, модельная программа, транзакция, TRANSMIT, UNDO, величина, переменная, текстовой редактор. Внутренние термины: поведенческое тестирование, ошибка, ввод, объект, дей- ственный тест, спецификация, состояние, тестирование. Графы — это основополагающий инструмент тестирования. Для тестирования используются масса различных моделей на основе графов, такие как граф потока управления, граф потока данных, дерево вызовов, граф конечного автомата, граф потока транзакций. Прежде всего мы обсудим абстрактные графы, чтобы ознако- миться с терминологией, которая будет полезна и неизменна при рассмотрении любых графов.
Отношения-. Определенная связь между объектами. Если А и Б — это объек- ты, a ft — отношение, A ft Б означает, что А находится в отношении ft к Б. Чтобы обозначать отношения, мы будем использовать курсив, например: А связано с Б, Сэм — отец Билла, А вызывает Б, объект данных А используется для вычисле- ния значений величин для объекта данных Б; за действием А следует действие Б. Задача тестирования состоит в том, чтобы убедиться, что все объекты имеют за- данные отношения друг с другом. Графы являются набором объектов, отношений между этими объектами и спе- цификаций (представленных, скажем, в виде списка), указывающих, какие объек- ты связаны и каким образом. Узел. Объекты в графах называются узлами. Узлы изображаются окружностя- ми. Задача тестирования — убедиться, что граф имеет все заданные узлы и не бо- лее того. Имя узла. Каждый узел имеет уникальное имя. Если объекты является фай- лами, имена узлов могут быть именами файлов; если объекты — это программы или операторы программ, имена узлов могут быть именами программ или метка- ми операторов соответственно. Ни свойства графа, ни свойства объектов, пред- ставленных в нем, не зависят от того, какие имена мы дадим узлам. Вес узла. Узлы могут иметь свойства. Эти свойства называются весом узла. В этой книге в качестве веса узла мы будем использовать, например: состояние программы, значение переменной, функцию, которая' описывает, какая из не- скольких величин может быть использована для вычисления чего-либо, имя дру- гого объекта. Задача тестирования — убедиться, что узлы с заданным весом имеют ожидаемый вес. Связь. Стрелка или линия, которая соединяет узлы, используется для иллю- страции конкретного отношения между этими узлами. Например, если суть от- ношения описывается как «А и Б — братья», мы соединяем А и Б линией, что- бы отметить этот факт. Если в нашей модели определено только одно отношение, мы можем не надписывать каждую связь, чтобы обозначить это отношение. Если между объектами может быть несколько отношений, мы можем помечать связи метками заданных отношений. На рисунке между узлами А и Б существуют два отношения: 0 — «А и Б — дети одних родителей» и S - «А и Б - друзья». Задача тестирования — проверить, что все связи находятся там, где и должны находиться, и что каждой связи соответствует определенное отношение. родителей
46 Глава 2 • Графы и отношения Параллельные связи. Две или более связей между двумя узлами. Параллельные связи используются, если между двумя узлами существуют несколько отношений. Имя связи. Каждая связь имеет уникальное имя. Существует несколько спо- собов обозначить связи. Мы будем часто использовать числа в качестве имен уз- лов, поэтому для имен связей мы будем применять строчные буквы. Другой спо- соб дать имя связи — использовать имена соединяемых узлов. Например, связь между узлами 17 и 34 мы назовем (17, 34). Это правило не годится для графов с несколькими связями между двумя узлами. Нам не обязательно всегда указывать имя связи, в таких случаях мы его просто опускаем. Ни свойства графа, ни свой- ства объектов и отношений, которые этот граф представляет, не зависят от того, как мы назовем связи. 17 Вес связи. Связи могут обладать свойствами. Такие свойства называются ве- сом связи. Простейшим возможным весом связи является факт ее существования. Примером веса связи может служить отношение или все отношения между двумя объектами. Если узлы обозначают шаги обработки, а связи показывают последо- вательность этих шагов, то весом связи может быть: время выполнения програм- мы по данному пути, вероятность выполнения именно этого пути (этой последо- вательности), тот факт, что будет вызван определенный объект данных. Свойства модели, изображаемой графом, напрямую зависят от веса связей. Задача тестиро- вания — убедиться, что связи с весом имеют ожидаемый вес. Направленная связь. Направленная связь изображается стрелкой. Направлен- ные связи используются для обозначения несимметричных отношений: отноше- ний, существующих лишь в заданном направлении. Примеры несимметричных отношений: А отец Б, за А следует Б, Б использует А, А вызывает Б. Большинство отношений в тестировании являются несимметричными, то есть в большинстве тестовых моделей используются направленные связи. Если ft — несимметричное отношение, и A ft Б, из этого не следует Б ft А. Задача тестирования — убедиться, что все направленные связи имеют заданные направления. Лито Огреь.
Ненаправленная связь. Связь, соответствующая симметричному отношению, то есть двустороннему отношению. Строго гозоря, ft — симметричное отноше- ние, если из факта A ft Б следует (в соответствии с природой отношения) Б ft А. Симметричные отношения изображаются двусторонними стрелками, поэтому мы обычно опускаем стрелки на концах линий. В первом примере на рисунке две противоположно направленные стрелки могут быть заменены или двусторон- ней стрелкой или простой линией, поскольку отношение «дети одних родителей» симметрично. В третьем примере, напротив, несмотря на то, что существуют от- ношения в обоих направлениях, они различны и несимметричны. Симметричные отношения довольно редко встречаются в тестировании, вот несколько приме- ров таких отношений: А и Б родственники, А и Б женаты, А и Б соседи по комна- те. Задача тестирования — убедиться, что все симметричные отношения на самом деле симметричны. Дети одних водителей Дети одних родителей Дети одних Граф. Граф — это набор узлов, имен узлоз, весов узлов, связей, имен связей, ве- сов связей и отношений между узлами. Если между двумя узлами существует от- ношение, то между ними есть связь. ВОПРОС: Что вы делаете, когда вам встречается граф? ОТВЕТ: Исследую его! Направленный граф. Граф, в котором все связи направлены. Большинство гра- фов в тестировании — направленные. Задача тестирования — убедиться, что на- правления связей совпадают с заданными.
Ненаправленный граф. Граф, в котором все связи ненаправленные. То есть ни одна связь в нем не имеет направления. Задача тестирования — убедиться, что все ненаправленные связи действительно являются двусторонними. Входящая связь. Связь, входящая в узел. В этом случае стрелка указывает на узел. Входной узел. Узел без входящих связей. Хотя у программы обычно есть вход- ные точки (например, BEGIN), графы, моделирующие поведение программ, могут и не иметь входных узлов. (НАЧАЛО)—----► Исходящая связь. Связь, выходящая из узла. В этом случае стрелка начинается на узле. Связь может быть одновременно и входящей, и исходящей. Это означает, что она начинается и заканчивается на одном и том же узле (например, цикл). Узел ветвления. Узел с двумя или более исходящими связями. В языках про- граммирования примерами узлов ветвления служат операторы CASE или IF-THEN- ELSE. На рисунке узел имеет три ветви. Обратите внимание, что это узел ветвления в графе, моделирующем поведение программы, в самой же программе соответ- ствующего ветвления может и не быть.
Выходной узел. Узел без исходящих связей. На рисунках изображены выход- ные узлы, поскольку ни одна стрелка на них не начинается. Хотя у программы обычно есть выходные точки (например, END), графы, моделирующие поведение программ, могут и не иметь выходных узлов. Путь. Поставьте карандаш на какой-либо узел на рисунке (например, на 14) и следуйте по стрелкам до другого узла (например, узла 17); это и есть путь от узла 14 к узлу 17. Однако если вы можете прочертить путь на графе, это не значит, что ваша программа может повторить этот путь. Путь в этом контексте не обязательно является путем в коде программы. В поведенческом тестировании мы рассматри- ваем пути в моделях, описывающих поведение программного обеспечения. Такие пути могут соответствовать путям в программе, а могут и не соответствовать им. Проходимый путь. Путь в модели, для которого существует такой набор вход- ных значений, что, используя их, программа может пройти по этому пути. Непроходимый путь. Путь в модели, который невозможно воспроизвести в программе, какой бы набор входных значений мы ни взяли. Путь вход—выход. Путь от входного узла к выходному узлу. Если отдельно не оговаривается, под термином «путь» подразумевается «путь вход—выход». Сегмент пути. Обычно путь, не являющийся путем вход—выход. Имя пути. Существует два способа назвать путь: по именам узлов вдоль это- го пути или по именам связей вдоль пути. Если мы назовем путь на следующем рисунке по именам узлов, то получим: «14,99,12,17», если по именам связей, то «кгш».
Длина пути. Существует два способа измерить длину пути. Можно восполь- зоваться числом узлов вдоль этого пути или количеством связей вдоль пути. В данной книге мы, как правило, будем считать связи. Предыдущий рассмотрен- ный путь был длиной в три связи или четыре узла. Цикл. Путь, в котором как минимум один узел встречается больше одного раза. Иначе говоря, это путь, в имени которого больше одного раза встречается имя узла (связи), в зависимости от того, как строится имя пути — перечислением уз- лов или перечислением связей. В примере на рисунке существует циклический путь akrmbakrmb или 7,14,99,12,17,7,14. Попробуйте найти на этом графе все цик- лические пути. Нециклический путь. Путь, в котором нет циклов. Это значит, что в его имени ни разу не повторяются имена узлов (связей). 2.3. Примеры графов, используемых в тестировании 2.3.1. Обзор В основе всех моделей тестирования лежат графы. Они описывают определенные отношения между определенными объектами. Если вы сможете определить все объекты и отношения между ними, вы сможете составить полную картину при по- мощи графа. Для построения модели (графа) вам надо определить: 1. Рассматриваемые объекты (узлы). 2. Отношения, которые должны существовать между узлами.
2.3. Примеры графов, используемых в тестировании 51 3. Какие объекты связаны друг с другом (связи). 4. Свойства, которыми могут обладать связи — веса связей. Отдельный вопрос — вдохновляет ли вас данная модель (граф) на написание действенного теста. Модель — дело вкуса. То, что нравится вам, может не нравить- ся мне и наоборот. Однако существуют модели, которые большинство людей счи- тает полезными. 2.3.2. Модель потока транзакций (глава 6) Объекты. Шаги в процедуре транзакций, такие как проверка платежной ведомо- сти, получение денег из банкомата. Каждому шагу в процессе транзакций соот- ветствует один узел. Отношение. «Предшествует следующему шагу». Например, расчет жалования предшествует расчету вычитаемых налогов. Связи. Соединяют следующие друг за другом шаги. Соответствуют отношению «предшествует» между двумя узлами. 2.3.3. Модель меню с конечным числом состояний (глава 9) Объекты. Меню, появляющиеся в окне, например, текстового редактора. Каждому пункту меню соответствует один узел. Отношение. «Может прямо вызвать», что означает существование пункта в ме- ню, выбор которого влечет за собой появление нового меню. Выбранный пункт меню определяет, какое именно меню второго уровня должно появиться. Связи. На каждый пункт в меню приходится по одной связи между узлами. Например, если меню А может (выбором соответствующих пунктов) вызвать меню Б, В, Г, то между АиБ, АиВ, АиГ существуют связи. 2.3.4. Модель потока данных (глава 5) Объекты. Определенные объекты данных. Каждому эзсмпляру (потенциально от- личимому от других величин) каждого объекта данных соответствует один узел. Отношение, «используется для вычисления значения». В равенстве X = 2Y + Z объекты Y и Z используются для вычисления значений X. Связи. Стрелка (связь) направлена от А к Б, если значение величины А исполь- зуется для вычисления величины Б. В нашем примере стрелки направлены от Y к X и от Z к X.
2.3.5. Модель времени выполнения Объекты. Линейные последовательности операторов в программе. Отношение «предшествует оператору». Например, READ filename предшествует оператору FOR.... Связи. Соединяют следующие друг за другом операторы. Соответствуют отно- шению «предшествует между двумя узлами». Обратите внимание, что операторы ветвления (такие как IF, CASE) имеют по одной исходящей связи на каждую ветвь. Свойства. 1. Связей — ожидаемое время выполнения (например, в микросекундах); 2. Операторов ветвления (например, IF...THEN...ELSE, CASE) — вероятности события для каждой их ветви (исходящей связи), что программа пойдет именно по ней. 2.4. Отношения 2.4.1. Обзор Отношения имеют определенные свойства и, следовательно, могут быть раз- биты на категории. Если, глядя на отношение, вы говорите: «О, это такой-то и такой-то тип отношений», то эти ваши знания вы сможете применить в конк- ретных случаях. Мы не будем рассматривать все свойства всех возможных от- ношений. Остановимся лишь на отношениях, наиболее часто используемых при тестировании. 2.4.2. Транзитивные и нетранзитивные отношения Отношение Й транзитивно, если из А Й Б и Б Й В следует АЙВ. Например, от- ношение быстрее — транзитивно. Если А быстрее Б и Б быстрее В, то, следова- тельно, А быстрее В. Примеры транзитивных отношений: можно достичь, больше, меньше, больше или равно, меньше или равно, зависит от, подмножество, находит- ся в проекции. Отношение, не являющееся транзитивным, — нетранзитивно. Примеры не- транзитивных отношений: друг, сосед, лжет, связан (напрямую). К примеру, из факта, что А лжет Б, а Б лжет В не следует, что А лжет В. В принципе А мог сол- гать В, но это никак не следует из того, что А лгал Б, а Б лгал В. Например, мы зна- ем, что А вообще не разговаривал с В. Хотя в большинстве случаев легко можно понять, являются отношения тран- зитивными или нет, в общем случае это не всегда так. Примером игры, построен- ной на транзитивности, может служить детская игра «Камень, ножницы, бумага» В этой игре ножницы режут бумагу, бумага покрывает камень, а камень тупит
ножницы. Дело усложняется тем, что все три отношения (режет, покрывает, ту- пит) эквивалентны в данном случае отношению сильнее, чем. На неоднозначности транзитивности построено также много других детских и взрослых игр. В наших интересах (поскольку это одна из задач тестирования) проверить, что все отношения, которые должны быть транзитивны, действительно транзитивны, и наоборот, если транзитивность не является свойством отношения, то необходи- мо проверить, что оно нетранзитивно. В естественных языках это бывает не всегда очевидно, поэтому спецификации могут вводить в заблуждение. Например, час- то встречающееся отношение связан в естественном языке может интерпретиро- ваться неоднозначно. Значит ли это, что из узла А можно достичь узла Б, или это значит, что А напрямую связан с Б? В первом случае отношение можно достичь должно быть транзитивно. Это значит, что если из А можно достичь Б, а из Б мож- но достичь В, то из А можно достичь В. Но отношение можно достичь не обяза- тельно транзитивно. Что, если мы добавим «прикоснувшись к руке»? Например, я могу достичь своей соседки, прикоснувшись к ее руке, а она, в свою очередь, мо- жет достичь своей соседки, прикоснувшись к ее руке, однако это не значит, что я могу достичь ее соседки, прикоснувшись к ее руке, если я, конечно, не орангутан или если мы не сидим очень близко. Всегда обращайте внимание и проверяйте транзитивность или нетранзитив- ность всех отношений из спецификации. Кроме этого, проверяйте программиста на его понимание транзитивности или нетранзитивности. Если понятие транзи- тивность неоднозначно трактуется в спецификации или программистом, то у вас плодородная почва для тестирования. 2.4.3. Симметричные и несимметричные отношения Отношение называется симметричным, если оно справедливо как в одну, так и в другую сторону. Это означает, что стрелка на графе направлена в обе стороны. Примеры: сосед, находится в браке. Отношение сосед симметрично, но не тран- зитивно. В английском языке для симметричных отношениях обычно используют обо- рот «А и Б находятся в отношении», вместо «А относится к Б». То есть мы гово- рим: А и Б находятся в браке, А и Б соседи и так далее. Отношение, не являющееся симметричным, называется несимметричным. То, что отношение не симметрично, еще не означает, что связь между парой узлов должна быть односторонней, это говорит лишь о том, что существование связи в обоих направлениях — не обязательное условие. Симметрия — это очень важное свойство отношений, и нам следует тестиро- вать отношения на симметричность. Например, если вы тестируете меню в про- дукте, управляемом через меню (то есть в продукте, работа с которым происходит посредством выбора определенных пунктов в меню), то, проверяя симметричность, вы фактически проверяете, всегда ли существует возможность возврата в преды- дущее меню. Аналогично если в программе (в текстовом редакторе, или, скажем, электронной таблице) есть функция UNDO, это значит, что большинство операций симметричны, поскольку всегда можно отменить действия оператора. Однако даже
идеальное UNDO не может быть полностью симметричным, поскольку существуют такие операции, как печать или отправить (PRINT, SEND), которые нельзя отменить. С симметричностью, как и с транзитивностью, часто возникает путаница в спе- цификациях, или по вине программистов. Естественные языки, как водится, тоже усложняют нам жизнь, однако в случае симметричности проблемы возникают, поскольку (в большей йли меньшей степени) в них симметричность подразумева- ется, а не постулируется явно. Всегда обращайте внимание и проверяйте симметричность или несимметрич- ность всех отношений из спецификации. Кроме того, проверяйте программиста на его понимание симметричности или несимметричности. Если понятие «симмет- ричность» неоднозначно трактуется в спецификации или программистом, то у вас появится плодородная почва для тестирования. 2.4.4. Рефлексивные и нерефлексивные отношения Отношение называется рефлексивным, если каждый узел находится в этом отно- шении с самим собой. Это означает, что каждый узел имеет связь, ведущую обрат- но на него (петля). Примеры рефлексивных отношений: знаком с (поскольку, если у меня нет амнезии, я знаком сам с собой), родственник, может коснуться, связан с, равен, эквивалентен. Если рефлексивность не выполняется для каждого узла в диаграмме, то отно- шение называется нерефлексивным. Следующие отношения нерефлексивные: друг (как часто можно услышать: «Он сам себе злейший враг»), выше, ниже. Рефлексивность — это возможность остаться в исходном состоянии. Ре- флексивность является важным свойством наших моделей (если она есть). Я как- то работал с неудачным текстовым редактором, в котором необходимо было что- то выбирать в каждом меню. Это можно было сделать, используя мышь (которой у меня в то время не было) или вводя ключевую букву, соответствующую первой букве в названии пункта меню. В таких случаях, если я ввожу неправильную бук- ву, я должен остаться в том же самом меню, но самонадеянная программа вмес- то этого делала выбор за меня и, как правило, неверный. Используемые меню не были рефлексивными в этом странном продукте.
Рефлексивность также чаще подразумевается, чем постулируется, и, следова- тельно, является хорошим объектом для поиска ошибок. Поскольку рефлексив- ность должна быть присуща каждому узлу, каждый узел должен быть проверен. Тестируйте рефлексивность по тому же принципу, что и транзитивность с сим- метричностью. 2.4.5. Классы эквивалентности и разбиения Отношение эквивалентности — симметрично, транзитивно и рефлексивно. Набор объектов, удовлетворяющих отношению эквивалентности, называется классом эквивалентности. Каждый объект из этого класса называется эквивалентным (в смысле данного отношения) любому другому объекту этого класса. Все методы, описываемые в этой книге, являются примерами тестирования пу- тем разбиения [HAMI.88, OSTR88, RICH81, RICH89, WHIT94], Эта стратегия построена на разбиении всех возможных входов на классы эквивалентности по какому-либо отношению эквивалентности. Я не буду в этой книге рассказывать, как создавать или находить подобные отношения, а познакомлю вас с набором уже готовых полезных отношений и, следовательно, полезных разбиений на клас- сы эквивалентности. Если у вас есть транзитивное отношение, то вы можете автоматически кон- вертировать его в соответствующее отношение эквивалентности и таким обра- зом разбить множество вводов на классы эквивалентности. Однако этот метод не рассматривается в данной книге. Дополнительную информацию вы найдете в [BEIZ90], глава 12. 2.4.6. Альтернатива графам 2.4.6.1. Граф — это визуализация Графическое представление графов, используемое в этой книге, является удоб- ным инструментом для обучения, поскольку большинство людей находит такое визуальное представление менее абстрактным. На практике, однако, за исклю- чением модельных задач, представленных в этой книге, графическое представ- ление графов слишком затруднительно. Вместо того чтобы рисовать картинки и использовать шаблоны (или их программные аналоги), мы представляем графы в виде таблиц или списков. Возможно, для вас в определенных случаях эти спо- собы представления окажутся полезны. Мне представляется правильным объяс- нить вам принципы их построения при первом же вашем знакомстве с графами. 2.4.6.2. Представление в виде таблиц или матриц Графы удобно представлять в табличной или матричной форме. Обычно исполь- зуется следующий порядок создания графа. 1. Нарисуйте двухмерный массив, размер которого равен числу узлов. 2. Если существует связь между узлом i и, например, j, задайте элемент [i, j] массива равным 1, в противном случае задайте его равным 0 или оставьте эту позицию пустой или же отметьте ее точкой.
3. Если число связей между двумя узлами больше одной, значение данного элемента должно быть равно числу связей. 4. Если связи обладают весами, впишите соответствующие веса. Обычно бывает удобно обозначать колонки и строки матрицы именами узлов. На рисунке показано подобное описание графа, внешний вид которого был при- веден в начале главы. 17 34 17 . 1 34 . На следующем рисунке представлен граф, описанный в пункте 2.2. 7 7 13 14 17 12 99 43 16 13 - - 1 • 14 - 1 • 1 . • 17 1 • • • 12 • - 1 . • 1 99 • • 1 • 43 1 • . 1 • • 16 2.4.6.3. Представление в виде списка Рассмотренные матрицы оказались по большей части пустыми. Это бывает часто, поскольку в графах число узлов, как правило, превышает число связей. Несмотря на то, что матрицы компактны, и их проще рисовать, чем графическую форму, ис- пользование такого формата часто затруднительно и приводит к ошибкам при ра- боте с большими матрицами. Более удобная форма представления — в виде списка связей. Чем объяснять, это проще показать на примере. Вот представление в виде списка последнего графа: 7: 12: 17.16 13: 12 99: 12 14: 13. 99 43: 7 17: 7 16: Если связи обладают весами, вы должны дсполнить элементы списка соответ- ствующими весами. К примеру, если взять имена связей в качестве их весов, то граф, изображенный на с. 50, будет представлен в следующем виде:
7: 14(a) 12: 17(т). 16(у) 14: 99(k). 13(t) 17: 7(b) 13: 12(z). 17(c) 16: 99(q). 43(h) 99: 12(г) 43: 12(х). 7(w) Вы можете изменять этот порядок записи по своему усмотрению, добавлять свойства, комментарии или что-то еще, чтобы список был понятным для вас и од- нозначно определял: 1. Начальный узел связи. 2. Конечный узел связи. 3. Все свойства связи. 4. Все свойства узла. Для больших графов удобно записывать каждую связь на отдельной стро- ке, оставляя место для комментариев и других аннотаций, относящихся к связям. Также может быть удобно записывать пояснения или ссылки на соответствующие параграфы так, как это сделал я: 7: 14(a) {перезапуск процесса: см. раздел 3.1.4.1.5.9} 14:99(к) (загрузка точки входа: см, раздел 3.2.4.5} 13(t) (инсталляция точки входа: см. раздел 3.3.1.7.5} 43:12(х) {устранимая ошибка: см. раздел 6.4.5} 7(w) {неустранимая ошибка: см. специальный раздел 6.4.6} 2.5. Основополагающие принципы тестирования 2.5.1. Обзор Ниже приведены основные шаги по использованию моделей на основе графов для разработки конкретных тестов. 1. Постройте граф. 2. Определите отношения. 3. Разработайте тесты проверки узлов (тесты, подтверждающие, что все узлы на месте). 4. Разработайте тесты проверки связей (тесты, подтверждающие наличие всех заданных связей и отсутствие лишних связей). 5. Протестируйте все веса. 6. Разработайте тесты для циклов. ВОПРОС: Что вы делаете, когда вам встречается граф? ОТВЕТ: Исследую его!
2.5.2. Построение графа 1. Определение узлов. • Какие объекты (узлы) представлены на данном графе? Каждому рас- сматриваемому объекту соответствует один узел. • Дайте имена узлам. Вы называете узлы по своему усмотрению, однако каждый узел должен иметь уникальное имя или идентификатор. Мне нравится использовать числа, но вы, возможно, отдадите предпочтение именам, несущим определенный смысл в контексте вашего приложе- ния. • Узлы могут обладать также свойствами (весами). Отметьте свойства (значения) для каждого узла. 2. Определение связей. • Каждая связь должна начинаться и заканчиваться на узле (это может быть один и тот же узел). Поскольку довольно часто предполагается на- личие входного и/или выходного узла, вам, возможно, придется доба- вить их в вашу модель. Если связь оборвана (то есть приходит ниоткуда или ведет в никуда), то в построении модели допущена ошибка. • Дайте имена связям. Если между парой узлов существует больше одной связи, то разумно дать каждой связи свое уникальное имя. Если два узла может соединять только одна связь, то давагь ей имя не обязательно. • Отметьте веса каждой связи. 3. Найдите входной и выходной узлы. В графе модели не обязательно при- сутствуют входной и выходной узлы, но часто есть оба. Если в графе все- таки есть входной и/или выходной узлы, то, по всей видимости, они игра- ют важную роль. Обозначьте все входные и выходные узлы соответственно. Например: 14 (ВХОД):... или 44 (ВЫХОД). Помните, что у входных узлов нет входящих связей, а у выходных нет исходящих связей. 4. Найдите все циклы. В графах моделей не обязательно присутствуют циклы, но если они есть, то они важны. Мы будем использовать специальные мето- ды тестирования циклов, поэтому вам надо будет найти все циклы на диа- грамме. Существуют способы сделать это автоматически (то есть алгорит- мически), но они не описываются в этой книге, см. [BEIZ90]. 2.5.3. Определение отношений 1. Начните с написания отношений на английском языке (или на вашем род- ном языке). 2. Ответьте ДА или НЕТ на следующие вопросы: • Оно рефлексивно?
• Оно симметрично? • Оно транзитивно? Если оно рефлексивно, то каждый узел должен иметь петлю. Если оно симмет- рично, то каждая связь должна быть двусторонней. Отношения на графе не обяза- тельно должны обладать этими свойствами. Более того, они могут обладать други- ми свойствами, не рассматриваемыми в этой книге (см. [BEIZ90], глава 12). Какими бы ни были свойства отношений, они должны проверяться при тестировании. 2.5.4. Проверка узлов Меньшее из всего, что вы можете сделать, — это провести достаточно тестов, для того чтобы убедиться, что все узлы именно такие, какими и должны быть. Такие тесты на- зываются проверкой узлов. У проверки узлов, однако, есть своя градация по степени совершенства тестов. Ниже приводится список тестов (в порядке возрастания при- оритета), которые надо провести, чтобы полностью выполнить проверку узлов. 1. Тесты, чтобы убедиться в наличии всех заданных узлов. Ни один узел не должен быть пропущен. 2. Тесты, чтобы убедиться в отсутствии лишних узлов (это может потребовать неограниченного числа тестов и поэтому быть неосуществимо). 3. Тесты, чтобы убедиться в корректности весов узлов, если они есть. 4. Если существуют входной и выходной узлы, то в завершение предыдущих шагов можно выбрать пути от входа до выхода и выбрать входные значения так, чтобы программа проследовала по каждому из заданных в модели пу- тей. Обычно задают несколько таких путей от входа к выходу (тестовых ва- риантов). Как уже говорилось, проверка узлов — это очень слабые тесты, на практике они оказываются настолько слабы, что фактически не используются. Все методы, из- лагаемые в этой книге, предполагают, что вы по меньшей мере выполнили провер- ку связей (см. ниже). Проверка связей, в свою очередь, подразумевает, что выпол- нены все тесты проверки узлов. 2.5.5. Проверка связей Следующее по эффективности действие, которое можно сделать, — это провести достаточно тестов, для того чтобы убедиться, что все связи именно такие, каки- ми и должны быть. Такие тесты называются проверкой связей. Ниже приводится список тестов (в порядке возрастания приоритета), которые надо провести, чтобы полностью выполнить проверку связей. 1. Тесты, чтобы убедиться в наличии всех заданных связей, — что ни одна связь не пропущена. 2. Тесты, чтобы убедиться в отсутствии лишних связей (Это может потребо- вать неограниченного числа тестов и поэтому быть неосуществимо).
3. Тестирование отношений. • Если отношение симметрично, то необходимо убедиться, что каждая связь является двусторонней: например, DO/UNDO. • Если отношение рефлексивно, то необходимо убедиться, что каждый узел связан сам с собой: например, DO nothing. • Если отношение транзитивно, то вы должны проверить его транзитив- ность в любой ситуации. Это делается следующим образом. Рассмотрим три объекта, А, Б и В, причем А связано с Б, а Б связано с В. То есть A Й Б и Б Й В. Показав (путем тестирования), что А Й Б — истина и Б Й В — ис- тина, необходимо показать, что АЙВ тоже является истиной. Сделайте это для каждой тройки узлов, в которой выполняются данные условия. 4. Если существуют входной и выходной узлы, то шаги 1-3, как правило, за- вершаются подбором путей от входа к выходу, при этом выбираются такие входные параметры, с которыми программа проследует по выбранным путям. Чаще всего для теста указывают несколько путей ВХОД/ВЫХОД (тестовых вариантов). Заметим, что если вы осуществляете проверку связей, вы обычно осуществляете и проверку узлов. Тем не менее, проверка связей в большин- стве случаев требует большего количества тестов, чем проверка узлов. При тестировании черного ящика, исключая патологические случаи, если вы разрабатываете тесты проверки связей, вы вместе с тем добиваетесь и проверки узлов. Однако вы вряд ли сможете убедиться, что не существует лишних узлов и что веса узлов, если узлы обладают весами, верны. Хорошей идеей будет добавле- ние в проверочный список инспектирования тестов и в ваш проект тестов требо- вания проверки узлов из раздела 2.5.4. 2.5.6. Тестирование весов Если связи имеют веса, проведите достаточное количество тестов, чтобы убедить- ся в правильности значения веса для каждой связи. То же самое сделайте для уз- лов, если они включены в модель. 2.5.7. Тестирование циклов Мы уделяем специальное внимание тестированию циклов, так как статистика ошибок показывает, что у программистов возникают проблемы с циклами. По этой причине циклам посвящена целая глава (см. главу 4). В этом разделе излага- ются лишь основы. В нашу задачу не входит анализ кода чтобы увидеть, есть в нем циклы или нет. Мы проводим тестирование циклов, если наша модель поведения программы включает в себя циклы. Цикл — это последовательность имен узлов, в которой как минимум одно имя узла повторяется. Если появляется другая последовательность повторяющихся имен узлов или она просто возможна, то у вас есть еще один цикл. Вы должны протестировать каждый цикл.
Тестирование цикла основано на том, сколько раз вы будете выполнять этот цикл. Вы можете совсем обойти цикл, можете пройти его один раз, два раза.... Максимальное количество проходов обозначим как п. В следующем примере есть узел, который является входом в цикл (А) и два узла, которые являются выход- ными в цикле (X и Y). 1. Обойдем цикл: АХЕ или AXYZE. (Я буду использовать оба пути.) 2. Пройдем цикл один раз: AXYVWXF или axyvwxyze. 3. Пройдем цикл два раза: axyvwxyvwxe или AXYnXYYWXYZE. 4. Пройдем цикл обычное число раз: A(X'Wt’D'ra ХЕ 5. Пройдем цикл максимальное число раз (n): А(XYVW)nXE и A(XYVW)"XYZE. 6. Пройдем цикл п-1 раз: A(XYVW)n lXE и А(XYVW)n ‘XYZE. 7. Попытаемся пройти цикл n + 1 раз: А( XYVW)T‘XE и A(XYVW)n,1XYZE. Рассмотрим два каких-нибудь узла в модели, скажем, А и В. Если существует путь от А к В (не обязательно прямая связь) и другой путь от В к А, и это верно для каждого А и В, то существует возможность, стартуя от любого узла, по какому-то пути прийти к любому другому узлу и вернуться назад к начальному узлу. Такие графы называются сильно связанными. Исчерпывающее тестирование цикла, как было определено, обычно является излишней тратой времени в сильно связанных графах. Очевидно, что граф с симметричными отношениями (или ненаправлен- ный граф) является сильно связанным, так как все стрелки направлены в обе сто- роны. Следовательно, тестирование циклов не является эффективным для графов с симметричными отношениями. 2.6. Резюме Вы освоили словарь и основную идею поведенческого тестирования. Может быть, материал был изложен более кратко, чем вы бы хотели. Как я уже говорил в README.DOC, эта глава — как подпрограмма, которую вы будете использовать н последующих главах при создании конкретных тестов. Рассматривайте эту гла- ву как объект в объектно-ориентированных программах, которые вы будете со- здавать в последующих главах. ООП, на мой взгляд, более абстрактно, нежели эта глава. Или же рассматривайте эту главу как игру, в которой вы должны победить. Используйте следующие вопросы для оценки того, что вы вынесли из этой главы.
2.7. Вопросы для самопроверки 1. Дайте определение: проходимый путь, несимметричное отношение, двоичное отношение, узел ветвления, оператор ветвления, дерево вызова, комментарий, граф потока управления, проверка (покрытие), оборванная связь, граф потока данных, направленный граф, направленная связь, входной узел, путь вход—вы- ход, класс эквивалентности, отношение эквивалентности, выходной узел, граф, матрица графа, входящая связь, нетранзитпвное отношение, нерефлексив- ное отношение, связь, проверка связей, представление списка связей, имя свя- зи, вес связи, цикл, нециклический путь, программа, управляемая через меню, узел, проверка узлов, имя узла, вес узла, исходящая связь, параллельные связи, стратегия тестирования путем разбиения, путь, длина пути, имя пути, сегмент пути, рефлексивное отношение, отношение, петля, соединять, сильно связан- ный граф, симметричные отношения, граф потока транзакций, транзитивные отношения, непроходимый путь, ненаправленный граф, ненаправленная связь. 2. Отношения могут быть: симметричными или несимметричными, рефлексив- ными или нерефлексивными, транзитивными или не транзитивными. Всего насчитывается восемь различных комбинаций. В табл 2.1. приведены примеры каждого типа отношений. Придумайте еще по три примера для каждого типа. Докажите принадлежность каждого к тому или иному типу (то есть протести- руйте их). Подсказка: попробуйте использовать Тезаурус Роже. Таблица 2.1. Примеры отношений Симметричное Рефлексивное Транзитизное Примеры нет нет нет любит, грубит, спорит, критикует, владеет нет нет да выше, длиннее нет да нет знаком с нет да да больше или равен да нет нет двоюродные сестры, женаты, обручены да нет да параллелен, сосед да да нет рядом с да да да равен 3. Определите, является ли отношение «находится в проекции» транзитив- ным? Придумайте ситуацию или способ освещения, при котором данное отношение нетранзитивно. 4. Рассмотрите отношение был объединен с с точки зрения его симметричнос- ти, рефлексивности, транзитивности. Приведите примеры и контрпримеры, подтверждающие ваши выводы. 5. Исследуйте следующие отношения (на предмет их симметричности, реф- лексивности, транзитивности) и подтвердите свои выводы, продемонстри- ровав отсутствие контрпримеров: А вызывает Б, А не равно Б, А согласен с Б, А эквивалентен Б, А согласуется с Б, А совместим с Б, А несовместим с Б, А — часть Б, А — вне Б, К лучше, чем Б, А доминирует над Б, А зависит от Б.
Тестирование потока управления 3.1. Обзор В этой главе в качестве основной модели, используемой при разработке тестов, рассматривается граф потока управления1. С помощью графа потока управления мы будем моделировать различные части формы 1040 декларации о доходах внут- ренней налоговой службы США (форма 1040 ВИС), сложность тестирования ко- торой сравнима с ее собственной сложностью. В дальнейшем модель будет ис- пользована для построения набора тестов по проверке связей. 3.2. Основные термины Внешние термины: алгебра, алгебраический, И (логическое), приложение, язык ассемблера, логическая ветвь, ошибка, оператор CASE, COBOL, код, завер- шать, сложность, вычисление, последовательный, ограничение, противоречие, управление, поток управления, копировать, программа для решения уравнений, ИСКЛЮЧАЮЩЕЕ ИЛИ (логическое), выполнять, выражение, крайние значе- ния, формальная модель, оператор IF, оператор IF-THEN-ELSE, оператор, ЛОЖЬ, оператор GOTO, реализация, ВКЛЮЧАЮЩЕЕ ИЛИ (логическое), приращение, неравенство, экземпляр, прыжок, логика, логическое выражение, логическое значение, LOTUS-123, сопровождение, матрица, пропущенные требования, мо- дель, ошибка модели, моделирование, имя, естественный язык, вложенный, НЕ 1 Поток управления задает последовательность действий при выполнении программы, он соот- ветствует цепочке операторов программы, последовательно передающих друг другу управление ком- пьютером. — Примеч. иаучн.ред.
(логическое), численный, оператор, ИЛИ (логическое), вставка, обработка, шаг обработки, программа, программист, программирование, псевдокод, реализм, перепрофилирование, выпуск, требования, перезапись, коммерческая презен- тация, предложение, система уравнений, программное обеспечение, специфика- ция, ошибка спецификации, электронная таблица, структурированная програм- ма, символическая подстановка, таблица, ошибка теста, проектирование теста, тестировщик, дерево, ИСТИНА, таблица истинности, значение истинности, неструктурированное программное обеспечение, значение, версия, текстовый редактор. Внутренние термины: проходимый путь, поведение, поведенческое тестирова- ние, тестирование черного ящика, слеп, покрытие ветви, ошибка, случайная кор- ректность, контроль конфигурации, покрываемые пути, входной узел, выходной узел, характеристика, граф, модель на основе графа, входящая связь, ввод, вход- ное значение, связь, покрытие связей, вес связи, представление графа в виде спис- ка связей, цикл, недостающая характеристика, недостающий путь, узел, имя узла, объект, оракул, итог, вывод, исходящая связь, параллельные связи, путь, сегмент пути, прототип, отношение, требование, спецификация, отрезок пути, тестовый вариант, тестовый комплект, метод тестирования, инструмент тестирования, не- проходимый путь, тестирование модуля, критерий соответствия. Логический предикат. Предложение или выражение, которое может прини- мать логическое значение ИСТИНА или ЛОЖЬ. Примеры: «Небо голубое», «Это утверждение ЛОЖНО», «Ваш родитель может предъявлять на вас права, пос- кольку вы зависите от его доходов», «Утверждается, что ваш ребенок, находится на вашем иждивении в соответствии с соглашением, принятым до 1985 года». Предикат выбора. Выражение, которое может принимать более двух значений и служит для выбора одного из нескольких вариантов. Пример: «Отметьте только одну позицию — (1) холост, (2) женат, заполняю совместную налоговую деклара- цию, (3) женат, заполняем раздельные налоговые декларации, (4) глава хозяйства, (5) вдовец». Термин «предикат» часто используется для обозначения как логиче- ских предикатов, так и предикатов выбора. Логическое И. В логических и формальных моделях «И» строго определяет- ся, следующим образом: А & Б будет истиной в том и только в том случае, если оба, А и Б, истинны. Однако в нестрого логических и неформальных докумен- тах, таких как бланки декларации на подоходный налог, слова и фразы, подоб- ные «еще», «также», «в дополнение к» и даже «или» могут на самом деле озна- чать логическое И. Логическое ИЛИ. В логических и формальных моделях «ИЛИ» всегда означает ВКЛЮЧАЮЩЕЕ ИЛИ, иначе «И/ИЛИ». Неформальное использование может быть различным и при интерпретации рекомендуется быть осторожным. Логическое НЕ. В логических и формальных моделях вам следует заключить предложение в скобки и поставить оператор НЕ впереди, как, например, «НЕ (ваш ребенок живет с вами)» вместо «ваш ребенок НЕ живет с вами». При нефор- мальном написании НЕ может стоять практически в любом месте в предложении, поэтому надо быть внимательным.
Составной предикат. Логическое выражение, включающее два или более пре- дикатов, связанных операторами И, ИЛИ или НЕ. Примеры: (1) «Ваш ребенок НЕ живет с вами И находится на вашем иждивении в соответствии с соглашением, принятым до 1985 года», (2) «(В 1994 году вы получали оклад И/ИЛИ чаевые) И ваш оклад вместе с чаевыми НЕ превысил 60600 $ И вы НЕ получали чаевые, подлежащие налогообложению по программе социального обеспечения или стра- хования здоровья по старости, о которых вы НЕ сообщали своему работодателю, И вы священнослужитель, получивший разрешение ВНС НЕ платить налоги с за- работков из этих источников, И вы платите налоги на индивидуальное предпри- нимательство с других доходов»1. Независимые предикаты. Два или более предикатов в пути модели называются независимыми, если их значения истинности (ИСТИНА/ЛОЖЬ) формируются независимо друг от друга. Коррелированные предикаты. Два или более предикатов в пути модели называ- ются коррелированными, если значение истинности для одного из них определя- ет значения истинности для всех остальных предикатов в этом пути. Пример: путь содержит два одинаковых предиката, и значение истинности для первого из них определяет значение истинности для второго предиката на этом пути. Комплементарные сегменты пути. Два сегмента пути, содержащие такие пре- дикаты, что если в одном сегменте предикат принимает значение ИСТИНА, то в другом предикат получает значение ЛОЖЬ и наоборот. 3.3. Отношения и модель 3.3.1. Основы Информация этой главы раскрывается в дополнительных источниках [ALLE72, CLAR76, EBER94, HOWD76, HOWD87, KRAU73, РЕТЕ76]. Объекты (узлы). Последовательность шагов обработки, такая, что выполнение любой части этой последовательности ведет за собой выполнение всей последова- тельности (если нет ошибок). Пример: Форма 1040. Следующие строки можно моделировать одним узлом, включающим в себя строки с 7 по 14, несколькими узлами, скажем, «7-8а-8Ь, 9- 10-11, 12, 13-14», или даже последовательностью из 9 отдельных узлов, по одно- му на каждую строку. 7. (введите) wages, salaries, tips (оклады, дополнительные доходы, чаевые). 8а. (введите) taxable interest income (налогооблагаемый доход). 8b. (введите) tax-exempt interest income (не облагаемый налогом доход). 9. (введите) dividend income (доход по дивидендам). 10. (введите) taxable refunds, credits, or offsets of state and local income taxes (налогооблагаемые платежи, кредиты, компенсации местного подоходного налога и подоходного налога в казну штата). 1 * 3 1 Я не выдумал это сам. Данная спецификация — это путь выполнения в форме SE ВНС, 1994. Можете убедиться сами. Подоходный налог 101 — определенно более напряженный курс, нежели про- граммирование 101 или тестирование 101. 3 Зах. 770
11. (введите) alimony received (полученные алименты). 12. (введите) business income or loss (доход или убыток от предпринимательской деятельности). 13. (введите) capital gain or loss (капитальные прибыль или убыток). 14. (введите) other gains or losses (другие прибыли или убытки). Ниже приведены некоторые из возможных моделей графов для данной специ- фикации. Отношения (связи): за ... непосредственно следует ... Если в предыдущем при- мере использовать один узел для каждого шага, то за узлом 9 непосредственно сле- дует узел 10, а за узлом 10 непосредственно следует узел 11, и так далее. Узел с предикатом. Узел с двумя или более исходящими связями, вес каждой из которых равен значению предиката. То есть ИСТИНА/ЛОЖЬ для логическо- го предиката и по одному из нескольких вариантов для предиката выбора. Узел с предикатом выбирает один из двух или более альтернативных путей, по которым может пойти процесс. Пример: Строки с 33b по 34 в форме 1040. 33b Если ваши родители могут утверждать, что вы находитесь на их иждивении, отметьте графу 33b. в противном случае не отмечайте графу 33b.Граф, моделирующий это предложение, изображен на рисунке. Узел с предикатом: «ваши родители могут утверждать, что вы находитесь на их иждивении?» Следующий узел в модели Узел выбора. Узел с двумя или более исходящими связями, вес каждой из ко- торых равен одному из значений величины выбора. Пример: строка 34 в форме 1040: Введите наибольшую из ваших льгот, перечис- ленных в бланке А, строка 29 ИЛИ обычная льгота для вашей фермы заполнения, ука-
занная ниже. Однако, если вы отметили какую-либо графу на строке 33а или Ь, сле- дуйте инструкциям для определения ваших стандартных льгот. Если вы отметили графу 33с. ваша стандартная льгота равна нулю, (а) холост = 13,800. (Ь) женат, запол- няю совместную налоговую декларацию = $6,350, (с) вдовец = $6,350 (d) женат, за- полняем раздельные налоговые декларации = $3,175, (е) глава хозяйства = $5,600. Следующий граф моделирует большую часть этого предложения. Узел 34.5 яв- ляется узлом выбора. Представление в виде списка связей более информативно и больше подходит для данного случая: 34 Стандартные льготы или детализированные льготы? 34.1 Детализированные 34.2 Стандартные 34.1 GOTO Бланк А. строка 29 35 34.2 Отмечена графа 33а или 33b? 34.3 ИСТИНА 34.4 ЛОЖЬ 34.3 GOTO Страница 22 35 34.4 Отмечена графа 33с? 34.6 ИСТИНА 34.5 ЛОЖЬ 34.5 Выберите 34.7 холост 34.8 совместная декларация 34.8 вдовец 34.9 раздельные декларации 34.10 глава хозяйства 34.6 Льготы = $0 35 34.7 Льготы - $3.800 35 34.8 Льготы - $6.350 35 34.9 Льготы - $3.175 35 34 10 Льготы = $5600 35 35 Продолжить модель Соединительный узел. Узел с двумя или более входящими связями. В предыду- щем примере узлы 34.8,35 были соединительными узлами.
Некоторые комментарии, касающиеся данной модели. 1. Узел 34 — узел с предикатом. Обратите внимание на использование здесь союза «или». Это не логическое ИЛИ. Это способ обозначить предикат1. 2. Предикат для узла 34.2 является составным предикатом, и ИЛИ здесь име- ет смысл включающего ИЛИ, поскольку можно отметить как одну графу, так и обе одновременно. Формальная запись данного предиката будет сле- дующей: «Вы отметили графу 33а ИЛИ вы отметили графу 33b (или обе)». Этот предикат также представляет интерес из-за использования в нем слова «однако». Ключевым словом в этом случае является не «однако», а следую- щее за ним «если». Вот более подробная модель для этого узла: 34.2 Отмечена графа 33а? 34.3 ИСТИНА 34.2.1 ЛОЖЬ 34.2.1 Отмечена графа 33b? 34.3 ИСТИНА 34.4 ЛОЖЬ А вот еще более подробная модель для этого узла: 34.2 Отмечена графа 33а? 34.2.2 ИСТИНА 34.2.1 ЛОЖЬ 34.2.1 Отмечена графа 33b? 34.3 ИСТИНА 34.4 ЛОЖЬ 34.2.2 Отмечена графа ЗЗЬ? 34.3 ЛОЖЬ Эта модель лучше первоначальной, поскольку она вскрывает сложность составного предиката и мы, скорее всего, обнаружим больше ошибок с ее помощью [MYER79]. Первая улучшенная модель может быть слепа к определенному типу ошибок, так как в ней не хватает критического подхода к предикату в узле 34.2. Вторая модель более сбалансирована, и в ней делается меньше предположений о способе реализации. Поэтому, хотя она и более сложная, она лучше ищет ошибки, и я выбираю ее. 3. Предикат в строке 33с является составным предикатом: «(Вы женаты, за- полняете раздельные налоговые декларации И льготы вашей супруги де- тализированы) ИЛИ вы иностранец с двойным гражданством». Здесь фи- гурирует включающее ИЛИ, поскольку вы можете быть иностранцем с двойным гражданством (что бы это ни значило) и ваша супруга может за- полнять налоговую декларацию раздельно и ее льготы могут быть дета- лизированы. Обратите внимание, что если вы не являетесь иностранцем с двойным гражданством, то должны выполняться три условия: (1) вы жена- ты, (2) вы заполняете налоговые декларации раздельно, (3) льготы вашей супруги детализированы. 4. Один из альтернативных пунктов в узле 34.5 скрыт под союзом «или». Это не логическое ИЛИ. Это способ обозначить параллельные связи и дополни- 1 На самом деле это не узел с предикатом, а нечто иное, что будет рассмотрено в главе 6 при из- учении тестирования потока транзакций. Это не настоящий предикат, поскольку вы можете выбрать оба альтернативных варианта.
тельные варианты выбора: «заполняю совместную налоговую декларацию» и «вдовец». 5. Узлы 34.1 и 34.3 входят в модель независимо от остальных узлов. Я мог бы включить в модель детали для них, но не стал, так как из узла 34.1 мы пе- ренаправляемся на бланк А, который может быть описан в нескольких дру- гих разделах книги. Разумно будет строить эти модели отдельно. По той же причине я буду отдельно моделировать узел 34.3. 6. Узлы 34.1, 34.3, 34.6, 34.7, 34.8, 34.9 и 34.10 в данной модели не существен- ны. Я мог бы связать обработку этих узлов, со связями, исходящими из узла 34.5 и включить их в веса связей, подобно тому, как приведено ниже. 34 Стандартные или Детализированные льготы? 34.2 Отмечена графа 33а или 33b? 34.4 Отмечена графа 33с? 34.5 Выберите 35 Детализированные/ GOTO Бл. А Стр. 29 34.2 Стандартные 35 ИСТИНА/GOTO СТР. 22 34.4 ЛОЖЬ 35 ИСТИНА/ Отч.= ТО 34.5 ЛОЖЬ 35 Холост/Отч. = $3.800 35 Совместная декларадия/Отч.= $6.350 35 Вдовец/Отч.= $6.350 35 Раздельные декларации/Отч.= $3.175 35 Глава хозяйства/Отч.= $5.600 35 Продолжить модель Эта модель эквивалентна приведенной выше, но не так полезна, поскольку более трудна для восприятия и связи в ней перегружены информацией. В целях понятности лучше использовать по возможности большее количе- ство узлов и связей. 7. В этих моделях не строится никаких предположений относительно про- граммного обеспечения и способов их реализации. Несмотря на то, что ис- пользование оператора IF-THEN для узлов 34,34.2 и 34.4 и оператора CASE для узла 34.5 представляется очевидным, существуют пути реализации без ис- пользования операторов IF-THEN и CASE. В поведенческом тестировании нам не следует слишком глубоко погружаться в детали конкретной реализации. 3.3.2. Моделирование составных предикатов Составные предикаты обманчивы, поскольку таят в себе подводные камни. Они так- же перспективны в смысле тестирования, так как программисты часто делают в них ошибки. Вы всегда можете подробно расписать составной предикат, для того чтобы вскрыть его сущность и построить его модель при помощи графа или таблицы. Ниже приводится модель на основе графа. Предположим, у вас есть составной предикат, со- стоящий из нескольких простых предикатов (то есть не составных), которые мы будем называть А, В, С. Например: «А&В ИЛИ С». Вы строите дерево предикатов с числом
ветвей, равным числу возможных вариантов. Для двух предикатов, число ветвей бу- дет равно четырем, для трех предикатов — будет восемь ветвей, для п простых преди- катов — 2" ветвей. На рисунке показан первый шаг. Порядок, в котором вы рассматриваете пре- дикаты, здесь не важен. Важно, чтобы все 2" ветвей (в нашем примере восемь) были рассмотрены. Следующий шаг — собрать все исходящие связи для случая ИСТИНА в узел со значением ИСТИНА, а все связи для случая ЛОЖЬ в узел со значением ЛОЖЬ, как показано на следующем рисунке. В итоге одиночный узел с составным предикатом «А&В ИЛИ С» заменяется на более подробную модель, на которой показаны все части предиката. Вам мо- жет показаться, что верхний узел с предикатом С избыточен, поскольку вне зави- симости от его значения результат будет — ИСТИНА. Тем не менее, он здесь не лишний, поскольку все это будет так при условии отсутствия ошибок в реализа- ции. Только путем тестирования всех восьми случаев (2П в общем случае) мы мо- жем убедиться, что логика, вне зависимости от способов ее реализации, не содер- жит ошибок. Вы можете отступиться и не тестировать точно все 2" случаев. Это здорово, если не обращать внимания на то, что ваше тестирование становится сла- бым и вы можете пропустить больше ошибок. Другой способ построить модель— использовать таблицу истинности (см. табл. 3.1) вместо дерева графа. Вы используете один узел для составного предика- та, с условием что все варианты должны быть проверены по таблице истинности.
Таблица 3.1. Таблица истинности А в с А&В ИЛИ С ИСТИНА ИСТИНА ИСТИНА ИСТИНА ИСТИНА ИСТИНА ЛОЖЬ ИСТИНА ИСТИНА ЛОЖЬ ИСТИНА ИСТИНА ИСТИНА ЛОЖЬ ЛОЖЬ ЛОЖЬ ЛОЖЬ ИСТИНА ИСТИНА ИСТИНА ЛОЖЬ ИСТИНА ЛОЖЬ ЛОЖЬ ЛОЖЬ ЛОЖЬ ИСТИНА ИСТИНА ЛОЖЬ ЛОЖЬ ЛОЖЬ ЛОЖЬ Напоминаю, что в таблицу истинности записываются состояния простых пре- дикатов, и просчитывается, какое из значений ЛОЖЬ или ИСТИНА будет иметь составной предикат для данной комбинации. Я использую таблицы для про- верки составных предикатов, состоящих более чем из трех простых предикатов. Добавление в граф четырех узлов для составного предиката, состоящего из двух элементов, не создаст в модели слишком большой путаницы. Однако уже трех- компонентный предикат сильно загрузит модель, а добавление четырехкомпонен- тного фактически нереально. Помните, что вы не можете не принимать в расчет возможность существования ошибок в вашей модели. 3.4. Методика 3.4.1. Основы Проектирование теста и его выполнение состоит из следующих шагов: 1. Изучите и проанализируйте требования на предмет их доступной для реа- лизации завершенности и самосогласованное™. Убедитесь в том, что спе- цификация корректно отражает требования, внесите поправки в специфи- кацию, если это не так. 2. Перепишите спецификацию в виде последовательности коротких предло- жений. Уделите специальное внимание предикатам. Разделите сложные предикаты на эквивалентные последовательности простых предикатов. Найдите узлы выбора и выпишите их в виде простых списков. Удалите лю- бые логические «И», которые не являются частью предикатов, вместо этого разбейте предложение на две части. 3. Однозначно пронумеруйте предложения. Впоследствии это будут имена узлов. 4. Постройте модель. 5. Проверьте модель — ваша работа так же подвержена ошибкам, как и работа программиста. 6. Выберите пути тестирования.
7. Активизируйте выбранные пути тестирования. То есть выберите такие входные значения, используя которые программа, при условии отсутствия ошибок, пройдет по пути, эквивалентному тому, который вы выбрали. 8. Предскажите и запишите вероятный итог каждого теста. 9. Определите критерий (критерии) соответствия для каждого теста. 10. Выполните тест. 11. Подтвердите итог. 12. Подтвердите путь. 3.4.2. Построение модели Как пример для иллюстрации процесса мы будем использовать строчки с 32 по 40 формы 1040 ВНС. Исходная спецификация приведена в Приложении А. Проще все- го мне будет это объяснить путем последовательного построения конкретной модели, комментируя процесс по мере ее развития. Мои комментарии выделены курсивом. Шаг 1: Проверить и обосновать требования. Вряд ли, что-то можно сделать, поскольку мы рассчитываем, что ВНС делает это за нас. Шаг 2: Переписать спецификацию. Что касается меня, я переписываю специ- фикацию, используя мой собственный тип псевдокода. Использование полуфор- мального языка (то есть псевдокода) помогает быть уверенным в однозначности при описании вещей Хотя это похоже на программирование, это не программиро- вание — это моделирование. Я использую представление в виде списка, так как это лете; хотя, когда я работал, я рисовал маленькие графы для того, чтобы убедиться в корректности потоков дан- ных для различных предикатов. Я включил мои некоторые наброски, чтобы помочь вам увидеть, как я мыслил. Несмотря на то, что построение и использование целого графа в виде рисунка чересчур громоздко, эти промежуточные наброски сегментов маленького графа помогут вам получить правильное представление о логике. 32: 33а1 введите adjusted_gross_1ncome (скорректированный_общий_доход) 33а1 33а2 положите счетчик_пометок равным нулю Необходимо отслеживать число пометок, которые мы делаем в форме. 33а2 ЗЗаЗ если 65 или старше Это узел с предикатом, то есть будет по крайней мере две исходящие связи. 33а4 если НЕ 65 или старше Пропустить приращение, если менее 65.
ЗЗаЗ 33а4 приращение счетчика_пометок Позднее нам будет необходимо знать общее число пометок, а этот способ моде- лирования не хуже любого другого. 33а4 33а5 если слеп Другой узел с предикатом. ЗЗаб если не слеп Пропустить приращение, если НЕ слеп. 33а5 ЗЗаб приращение счетчика_понеток Увеличение числа пометок, если слеп. ЗЗаб 33а7если супругу 65 или он старше Заметим, что в действительности логика здесь намного сложнее. Если бы наша модель была для всей формы 1040, то нам следовало бы учитывать корреляцию со строчками 1-5, принимая во внимание способ заполнения декларации. Только об- ладающие статусом (2) Женат или статусом (5) Вдоеа (вдовец) могли бы делать отметки в этой и следующей графе. В реальной модели вы бы предварили этот и следующий узел с предикатом другим узлом с предикатом, который спрашивает: «Женат и заполняет совместную налоговую декларацию ИЛИ вдовец с детьми на иждивении?» Если предикат является ИСТИНОЙ, вы выполняете узлы с ЗЗаб по 33а9, иначе вы переходите к узлу ЗЗаЮ. Однако для того чтобы сохранить при- емлемый размер этой модели, мы не будем гнаться за реалистичностью и допус- тим, что этот сегмент не зависит ни от каких предыдущих сегментов и логики Графическая реализация этой части модели приведена на рисунке. 33а8 если супругу НЕ 65 или больше 33а7 33а8 приращение счетчика_пометок 33а8 33а9 если супруг слеп ЗЗаЮ если супруг НЕ слеп 33а9 ЗЗаЮ приращение счетчика_пометок Узел ЗЗаЮ является излишним, так как мы изменяли счетчикпоиеток по мере прохождения пути; однако я предпочитаю быть уверенным, что существует по крайней мере один узел (для начала) для каждого утверждения в спецификации. ЗЗЬЗ ЗЫ Если ваши родители могут предьявить на вас права Узел с предикатом.
33с Ваши родители не могут предъявить на вас права ЗЗЫ 33с Пометьте графу ЗЗЬ ЗЗсЗ 33с1 Женат, заполняю отдельную декларацию Составной предикат. Если бы вы посмотрели инструкции ВНС, вы бы нашли еще больше логики в модели. Для того чтобы оставаться в разумных границах, мы проигнорируем инструкцию следовать инструкциям, но в реальных задачах у вас нет такого выбора. Для того чтобы не было скрытой сложности, я разбил пре- дикат на составные части. Моя модель для этого раздела приведена на рис. 3.8. Возможны также и другие, эквивалентные модели. Я тут кое-что упустил. Первое раз, когда я это делал, я забыл о возможности женатому человеку подать заявку отдельно от супруга, льготы которого не дета- лизированы, учитывая, что я иностранец с двойным гражданством. Поэтому мне пришлось вернуться назад и добавить предикатный узел в 33с4. Здесь мне вновь по- могли схемы. Эта часть модели показана на следующем рисунке. Женат, раздельные декларации? ЗЗсЗ Зс2 Неженат, подает декларацию отдельно 33с1 33с4 Льготы супруга не детализированы ЗЗсЗ Льготы супруга детализированы 33с2 ЗЗсЗ Двойное гражданство. 34 Нет двойного гражданства ЗЗсЗ 34 Пометьте графу 33с 33с4 34 Нет двойного гражданства Это не избыточность. ЗЗсЗ Двойное гражданство 34 34.1 Ваши льготы детализированы? 34.2 Ваши льготы не детализированы Узел 34 — очень интересный случай. Он похож на предикатный узел, но на са- мом деле это не так. Это пример того, что мы называем разбиением транзакции (смотрите главу 6.). Для того чтобы следовать инструкции (смотрите дальше узел 34.13), то есть взять большую из детализированных или стандартных льгот, вы должны выполнить оба вычисления, как для стандартной льготы, так и для де- тализированной льготы. Фактически мы должны обрабатывать обе части парал-
лельно, иначе нечего будет сравнивать в узле 34.13. Вы наверняка это делаете при заполнении своей налоговой декларации. 34.1 34.12 Используйте бланк А. строку 26 Здесь кроется еще одна целая модель. 34.2 34.3 НЕ пометили графу 33а 34.4 Пометили графу 33а 34.3 34.4 Пометили графу ЗЗЬ 34.5 НЕ пометили графу ЗЗЬ Подождите минутку! А что насчет человека, которому 65 лет или больше, И/ИЛИ который слеп И который находится на иждивении у своих родителей или у кого-нибудь еще. Покрывает ли модель этот случай? 34.4 34.12 Стандартные льготы по инструкции 34.5 34.6 Помечена ли графа 33с? 34.7 Графа 33с не помечена 34.6 34.12 Стандартная льгота - О 34.7 34.8 Холост Предикат выбора. 34.9 Глава хозяйства 34.10 Женат, заполняем совместную налоговую декларацию 34.11 Женат, заполняю отдельную налоговую декларацию 34.8 34.12 Стандартная льгота - $3.800 34.9 34.12 Стандартная льгота = $5 600 34.10 34.12 Стандартная льгота = $6 350 34.11 34.12 Стандартная льгота = $3.175 Эта модель тоже может быть выражена при помощи графа на следующем рисунке.
34.12 34.13 Пустой узел для большей ясности 34.13 34.14 Стандартные льготы больше детализированных льгот? 34.15 Стандартные льготы НЕ больше детализированных льгот? 34.14 35 Использовать стандартный список 34.15 35 Использовать детализированный список 35 36 Вычесть строку 34 из строки 32 36 36.1 Строка 32 « $83.850 36.2 Строка 32 > $83.850 36.1 37 $2.450 exemptions (освобождения) 36.2 37 Согласно инструкции 37 38 Мах(0, строка_35 - строка 36) Обозначает еще один предикат, но скрывает сегмент пути. Давайте делать правильно. 37 37.1 37.2 38 37.1 38 37.2 38 38.1 Строка_35 - строка_36 Больше нуля Меньше или равен нулю Введите ноль в строке 37 tax table (таблица налогов) Выглядит привлекательно. На первый взгляд это выглядит так, как будто есть пять взаимоисключающих возможностей: (а) таблица налогов, (Ь) налоговая та- рифная сетка, (с) бланк D, (d) форма 8615 или (е) форма 8814. Однако, изучая формы 8615 и 8814, я замечаю, что они могли бы представлять собой две дополни- тельные позиции для каждой из первых трех опций. Я пытался получить объясне- ния в ВПС, но не получил. Я позвонил моему бухгалтеру, и он спросил, будет ли это «специальной консультацией», но я ответил: «Не беспокойся, Чарли». Такого рода исследования вы можете проводить при создании практической модели, но в этом примере я буду рассматривать пять различных вариантов. 38 38.2 tax rate schedule (налоговая тарифная сетка) 38.3 Бланк С 38.4 Форма 8615 38.5 Форма(ы) 8814 Заметим, что может быть несколько форм 8814, но мы не говорим о том, что- бы суммировать эти формы. Такие особенности должны быть исследованы. Здесь нам следует взять вместе все формы 8814, так как они должны быть заполнены на каждого ребенка, чей интерес и дивиденды вы представляете при заполнении нало- говой декларации. 38.1 39 налог в соответствии с tax table (’аблицей налогов) 38.2 39 налог в соответствии с tax rate schedule (налоговой тарифной сеткой). 38.3 39 налог в соответствии с бланком С. 38.4 39 налоги в соответствии с формой 8615 38.5 39 налоги в соответствии с формой (формами) 8814 39 39.1 дополнительные налоги в соответствии с формой 4970 39.2 НЕТ дополнительных налогов по форме 4970 39.1 39.3 заполните налоговую форму 4970 39.2 39.3 поставьте ноль для дополнительных налогов в строке 39 39.3 39.4 дополнительные налоги по форме 4972 39.5 НЕТ дополнительных налогов по ферме 4972 39.4 40 Добавьте налоги из формы 4972 в строку 39
Я смоделировал это именно таким образом, так как из налоговых форм мне по- казалось, что можно облагать налогом по форме 4970 или 4972 или сразу по обеим. Такие вещи не очевидны, и вы должны их исследовать. 39.5 40 Ничего не делайте 40 41 Добавьте строки 39 и 40 Ужасно? Построение такой модели с простой на вид спецификацией стоило многих усилий. Это заняло у меня пять часов, включая время, затраченное на ри- сование презентабельных фрагментов графа и пояснительные комментарии, ко- торые я бы и не делал, если бы я создавал настоящий план тестирования. Но все эти комментарии и внутренние монологи — это неплохая идея. Кто-нибудь (вроде вас), может быть, поблагодарит за это. Исходя из опыта и практики, на построение данной модели должно затрачи- ваться максимум два-три часа. При большем объеме исследования это, вероят- но, займет больше времени. Заметим, что мои графические модели по ходу дела становились проще. В последней модели, например, детализирован только поток управления. Это сделано преднамеренно. Вы используете графические формы для того, чтобы быть уверенным в правильности логики, однако вам также необ- ходимо документировать детали содержания в виде списка. По ходу дела я менял обозначения. Граф, который мы рассматривали в пункте 3.1, имеет формат иня_узла/действие/значение предиката, тогда как последний фор- мат это имя_узла/иня_узла/действие или значение предиката/конментарии. Опираясь на последние обозначения, связи легко отметить и контролировать, но более ранние обозначения ближе к первоначальной форме изложения. При этом не имеет зна- чения, какой формат вы используете. Выберите что-то одно, что имеет все необхо- димые данные и чего вы можете придерживаться. Другая причина состоит в том, что это не программирование. Я не пытался использовать структурированное мышление, при этом мои модели полны GOTO и подобных ему вещей. В настоящее время при реализации явной логики обычно ограничиваются строго структурированными конструкциями. Я здесь предпочи- таю GOTO и другие бесструктурные вещи, так как при этом не надо далеко отхо- дить от естественного языка спецификации. Большинство естественно-языковых спецификаций бесструктурно. Если вы слишком отдаляетесь от первоначальной формулировки для принудительного использования, скажем, вложенного дере- ва IF-THEN-ELSE, то увеличивается вероятность ошибки моделирования, которая, в свою очередь, приводит к тестовым ошибкам или необнаруженным ошибкам программы. 3.4.3. Выбор путей тестирования 3.4.3.1 Основы Вы ничего не выиграете, уменьшая количество тестов. Лучше использовать про- стые, очевидные тесты, чем выполнять работу с меньшим количеством более гро- моздких тестов. Предыдущий пример можно, вероятно, сжать до 10 тестов, но нам следует использовать большее их число, если при этом тестирование проходит максимально чисто и больше согласовано с требованиями.
Очень часто выбор путей тестирования и их активизацию выполняют одно- временно, так как корреляция предикатов может воспрепятствовать проходу про- граммы по произвольно выбранным путям. Хотя это и хорошо на практике, ди- дактически это неправильно, поэтому мы сначала выберем пути тестирования, а затем, в следующем разделе, будем их активизировать. Мы создаем путь, добавляя сегмент за сегментом, начиная с входного узла и продолжая до выходного узла. Мы выбираем наши сегменты, начиная с точек, где потоки управления расходятся из одиночного узла, и продолжаем до тех пор, пока потоки управления опять не сойдутся в один узел. Примеры: 32-33а4, 33а4- ЗЗаб, 33с-34. Поступая таким образом, мы строим путь, комбинируя ранее вы- бранные сегменты. Понятно, что комбинировать сегменты пути можно только в таких, одноузловых точках схождения. В каждом предикате мы выполняем вет- вление, выбирая возможные значения (например, значения ИСТИНА/ЛОЖЬ), тем самым расщепляя пути, построенные до этой точки. В узлах 32 или 33а 1 нет выбора; все наши тесты должны начинаться с узлов 32,33а 1. Первым предикатом является узел 33а2. Ветвление здесь соответствует выбо- ру из значений ИСТИНА или ЛОЖЬ, приводя к следующим двум семействам тестов: А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. 33а4 А2: 32. 33а1. ЗЗа2(Л). 33а4 Следующий предикат — это узел 33а4 {слеп?). Он, очевидно, является незави- симым от предыдущего предиката 33а2 {65лет или старше?). Поэтому, хотя пути снова расщепляются, нет необходимости добавлять это з тесты. Для определен- ности зафиксируем значение предиката ИСТИНА в пути А1, а значение ЛОЖЬ — в пути А2. А1: 32. 33а1, ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб В узле ЗЗаб мы спрашиваем, исполнилось ли супругу 65 лет, а в 33а8 мы спра- шиваем, слеп ли ваш супруг. Рассматривая эти первые четыре предиката, вы мо- жете увидеть, что они в итоге обеспечивают 16 возможных путей прохода через этот сегмент спецификации. Мы, конечно, можем подготовить в этой точке 16 тес- тов, проверяющих все 16 комбинаций значений этих четырех предикатов, но это был бы плохой выбор. Тем самым мы бы пытались тестировать маловероятные ошибки. Для проверки связи от узла 32 до узла ЗЗЬ требуются только два сегмен- та пути. Какие из них нам следует взять? Любой из двух комплементарных путей подойдет. Пути на отрезке от 32 к ЗЗЬ могут привести к значениям счетчика_по- меток от нуля до четырех. Из опыта мы знаем, что программисты склонны вводить путаницу с граничными значениями (нулем или четырьмя), поэтому мы должны выделить эти варианты, следовательно, эту логику желательно проверить с помо- щью тестов, в которых оба — и человек, заполняющий форму, и супруг — слепы и старше 65 лет. А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9. ЗЗаЮ. ЗЗЬ А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ
Следующий предикат — это узел 33b. Вначале я допустил ошибку и в результа- те получил проблемы с активизацией. Я не забегаю вперед, чтобы увидеть, может ли этот предикат заблокировать дальнейшие пути, завершаемые в сегменте 34-35. Вот два варианта для этого сегмента: В1: ЗЗЬ(И), ЗЗЫ, 33с и В2: ЗЗЬ(Л), 33с. Я не знаю, какие комбинации блокируются позже, поэтому в этой точке создаю четыре варианта, комбинируя наборы А и В. Позднее мы исключим тесты, кото- рые не выполняются. Получаем следующее семейство тестов. В1АЮ 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9. ЗЗаЮ. ЗЗЬ(И). ЗЗЫ. 33с В2А1; 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9, ЗЗаЮ. ЗЗЬ(Л). 33с В1А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗ(Л). ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. 33с В2А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬСЛ). 33с Следующий сегмент — это 33с-34. Существует пять возможных путей через этот сегмент, и все пять необходимы для покрытия связей. Пять сегментов: СЮ ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34 С2: ЗЗс(И). ЗЗсКИ). ЗЗсЗ. 34 СЗ: ЗЗС(И). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34 С4: ЗЗс(Л). ЗЗс2(Л). 34 С5: ЗЗсСИ). ЗЗсКЛ). ЗЗс4(Л). 34 Здесь целесообразна быстрая проверка. Я просмотрел четыре предиката (33с, 33с 1, 33с2 и 33с4) в предыдущем списке, чтобы быть уверенным, что каждый преди- кат принимает оба значения (ИСТИНА и ЛОЖЬ) в каком-нибудь сегменте теста. С1В1А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9. ЗЗаЮ. ЗЗЬ(И). ЗЗЫ. ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34 С2В1А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗс(И). ЗЗсКИ). ЗЗсЗ. 34- СЗВ1А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И), 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗсСИ). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34 С4В1А1: 32. ЗЗаЮ ЗЗаЗСИ). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗсСЛ). ЗЗс2(Л). 34 С5В1А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗсСИ). ЗЗсКЛ). ЗЗс4(Л). 34 С1В2А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСЛ). Зс(Л). ЗЗс2(И). ЗЗсЗ. 34 С2В2А1: 32. ЗЗаЮ ЗЗа2СИ). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬ(Л). ЗЗсСИ). ЗЗсКИ). ЗЗсЗ. 34 СЗВ2А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗабСИЮ 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСЛ). ЗЗсСИ). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34 С4В2А1: 32. ЗЗаЮ ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСЛ). ЗЗсСЛ). ЗЗс2(Л). 34 С5В2А1: 32. ЗЗаЮ ЗЗаЗСИ). ЗЗаЗ. ЗЗа4СИ). ЗЗаб. ЗЗаб(И). 33а7. ЗЗаЗСИ). 33а9. ЗЗаЮ. ЗЗЬСЛ). ЗЗсСИ). ЗЗсКЛ). ЗЗс4(Л). 34 С1В1А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗСЛ). ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗсСЛ). ЗЗс2(И). ЗЗсЗ. 34 С2В1А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗСЛ). ЗЗаЮ. ЗЗЬСИ), ЗЗЫ. ЗЗсСИ). ЗЗсКИ). ЗЗсЗ. 34 СЗВ1А2: 32. ЗЗаЮ ЗЗа2СЛ). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗСЛ). ЗЗаЮ. ЗЗЬСИ). ЗЗЫ. ЗЗсСИ). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34 С4В1А2: 32. 33а1, ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗСЛ). ЗЗаЮ. ЗЗЬСИ). ЗЗЫ.
33с(Л). ЗЗс2(Л). 34 С5В1А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаЗ(Л). ЗЗаЮ. ЗЗЬ(И). ЗЗЫ ЗЗс(И). ЗЗсКЛ). ЗЗс4(Л). 34 С1В2А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34 С2В2А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И). ЗЗс1(И). ЗЗсЗ. 34 СЗВ2А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34 С4В2А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(Л). 34 С5В2А2: 32. ЗЗаЮ ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И). ЗЗсКЛ). ЗЗс4(Л). 34 Небольшая подсказка. Используйте особенности вашего текстового редактора для предотвращения ошибок. Для начала я скопировал сегменты с Cl по С5, азатем я использовал копирование и вставку для вставки предыдущих сегментов (В1А2- В2А2), перед С1-С5. Так как узел 33с не был включен в копируемый блок, мне не пришлось удалять его копии. Такой способ является простым и более надежным. Ниже приведены восемь возможных сегментов пути от узла 34 до узла 34.12. D1: 34(И). 34.1. 34.12 D2: 34(Л). 34.2(H). 34.4. 34.12 D3: 34(Л). 34.2(Л). 34.3СИ). 34.4. 34.12 D4: 34(Л). 34.2СЛ). 34.301). 34.5(H). 34.6. 34.12 D5: 34(Л). 34.2СЛ). 34.3СЛ). 34.5(Л). 34.7(ХОЛОСТ). 34.6 34.12 D6: 34(Л). 34.2СЛ). 34.3(Л). 34.501). 34.7(ГЛАБА). 34.9. 34.12 D7: 34(Л). 34.2СЛ). 34.3(Л). 34.5(Л). 34.7(СОВМЕСТНО). 34.10, 34.12 08: 34(Л). 34.2СЛ). 34.301). 34.5СЛ). 34.7(РАЗДЕЛЬНО). 34.11. 34.12 Если мы продолжим комбинирование, то у нас получится 20 вариантов, скомби- нированных с восемью вариантами. То есть всего 160 вариантов для рассмотрения. Поэтому стоит исключить некоторые варианты по ходу рассмотрения. Это еще одна причина, почему активизация и выбор пути обычно выполняются вместе. Мы исключаем пути посредством удаления комбинаций, которые не могут быть выполнены, так как предикаты блокируют друг друга. Я создал таблицу из 20 строк и 8 столбцов (табл. 3.2). Заголовками строк были сегменты с С1В1А1 по С5В2А2, а заголовками столбцов — сегменты от D1 до D8. 1а. Значение ЛОЖЬ в узле 34.5 означает, что графа 33с не была помечена, по- этому путь не может пройти через узел ЗЗсЗ, соответствующий помеченной графе. Я использовал текстовый редактор, чтобы найти те сегменты, кото- рые содержат в себе узел ЗЗсЗ. Это оказались С1, С2 и СЗ. Их нельзя ском- бинировать с D5-D8, так как в этих вариантах должна быть помечена графа ЗЗсЗ. Поэтому следует вычеркнуть их из таблицы. 1Ь. Напротив, значение ИСТИНА в узле 34.5 означает, что графа 33с была по- мечена, поэтому путь проходил через узел ЗЗсЗ. Следовательно, D4 не ком- бинируется с С4 и С5. 2а. Если графа 33b помечена, логика не позволяет выбрать в узле 34.3 исходя- щую ветвь, соответствующую значению ЛОЖЬ. Следовательно, если вы- полняется узел 33bl, сегменты D4-D8 выполняться не могут. Используя
поиск по узлу ЗЗЫ (где проверяется пометка графы ЗЗЬ), мы видим, что лю- бой сегмент, включающий вариант В1, не может быть скомбинирован с сег- ментами D4-D8. 2Ь. И наоборот, если графа ЗЗЬ не помечена (вариант В2), логика не позво- ляет выбрать в узле 34.3 исходящую ветвь, соответствующую значению ИСТИНА, и вариант D3 не может объединяться с любыми путями, кото- рые включают ЗЗЬ(Л). Это пути, содержащие в себе В2. Поэтому любые сег- менты с В2 не комбинируются с D3. За. Если графа 33а помечена, тогда сегменты D3-D8 можно удалить. Графа 33а помечается в узлах ЗЗаЗ, ЗЗаб, 33а7 и 33а9. Проводя заново поиск наших сегментов, мы видим, что это любые сегменты, содержащие А1. Поэтому А1 не комбинируется с D3-D8. Таблица 3.2. Определение графа состояний СЕГМЕНТ D1 D2 D3 D4 D5 D6 07 D8 С1В1А1 хххх хххх хххх хххх хххх хххх С2В1А1 хххх хххх хххх хххх хххх хххх хххх СЗВ1А1 хххх хххх хххх хххх хххх хххх хххх С4В1А1 хххх хххх хххх хххх хххх хххх С5В1А1 хххх хххх хххх хххх хххх хххх хххх С1В2А1 хххх хххх хххх хххх хххх хххх С2В2А1 хххх хххх хххх хххх хххх хххх хххх СЗВ2А1 хххх хххх ХХХХ хххх хххх хххх хххх С4В2А1 хххх ХХХХ ХХХХ хххх хххх хххх С5В2А1 хххх хххх хххх хххх хххх хххх хххх С1В1А2 хххх хххх хххх хххх хххх хххх С2В1А2 хххх хххх хххх хххх хххх хххх СЗВ1А2 хххх хххх хххх хххх хххх хххх хххх С4В1А2 хххх ххх> хххх хххх хххх хххх С5В1А2 хххх хххх хххх хххх хххх хххх хххх С1В2А2 хххх хххх хххх хххх хххх хххх С2В2А2 хххх хххх хххх хххх хххх хххх СЗВ2А2 хххх хххх хххх хххх хххх хххх хххх С4В2А2 хххх хххх хххх хххх С5В2А2 хххх хххх хххх хххх хххх хххх хххх 3b. Наоборот, если графа 33а (А2) не помечена, то можно не учитывать D2. 4а. Если вы женаты и заполняете форму раздельно (проверяется 33с), то вы не можете заполнять форму совместно в 34.7. Следовательно, любые сегмен- ты С1В1А1-С5В2А2, включающие ЗЗс(И), не могут комбинироваться с D7. Это все сегменты, содержащие С2, СЗ или С5. 4Ь. И наоборот, любой сегмент, содержащий С1 или С2, не может комбиниро- ваться с D8. Так как ЗЗс(Л ) не означает заполнение раздельных деклараций и 34.7 (РАЗДЕЛЬНО) этому противоречит.
5. Если вы холосты (34.7(XOJIOCT)-D5), или вы глава хозяйства (34.7 (ГЛАВА)-Об), льготы вашего супруга не могут быть детализированы. Следовательно, сегменты с ЗЗс1(И)-С2 не могут комбинироваться с сег- ментами D5 или D6. Это нам ничего не дает, но, между прочим, мы уже ис- ключили 116 вариантов из 160 возможных. 6а. Мы знаем, годами заполняя совместную налоговую декларацию, что если ваши льготы детализированы, то льготы вашего супруга должны детализи- роваться и наоборот. Следовательно, любые варианты с ЗЗс1(Л)-СЗ и С5 не сочетаемы с 34(И)-В1, и исключается более восьми случаев. 6Ь. Двигаясь в обратном направлении, мы можем понять, что С2 не может ком- бинироваться с D2-D8. 7. Если вы женаты, заполняете форму раздельно, и льготы вашего супруга не детализированы, и он не является иностранцем (С5). вы не можете быть хо- лосты (D5) или быть главой хозяйства (Об). Сейчас мы можем продолжить выбор путей. Рассматривая неотмеченные ячей- ки в таблице, видим, что для D5, D6, D7 и D8 вариантов нет. Они должны комби- нироваться соответственно с С4В2А2, С4В2А2, С4 В2А2 и С5В2А2. D5C4B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(Л). 34(Л). 34.2(Л). 34.3(Л). 34.5(Л). 34.7(Х0Л0СТ). 34.8. 34.12 D6C4B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(Л),34(Л). 34.2СЛ). 34.3СЛ). 34.5(Л). 34.7(ГЛАВА). 34.9. 34.12 D7C4B2A2: 32. 33а!. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(Л). 34(Л). 34.2СЛ). 34.3(Л). 34.5СЛ). 34.7(СОВМЕСТНО). 34.10. 34.12 D8C5B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗС(И). ЗЗсКЛ). ЗЗс4(Л). 34(Л>. 34.2СЛ). 34.3СЛ). 34.5(Л). 34./(РАЗДЕЛЬНО). 34.11. 34.12 У нас есть три варианта для D4. В данный момент я возьму вариант С1, приво- дящий к D4C1B2A2. D4C1B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34(Л). 34.2СЛ). 34.3(Л). 34.5(H). 34.6. 34.12 В этом месте мы еще должны включить А1, В1, С2, СЗ, DI, D2 и D3. D3 может сочетаться только с комбинацией В1А2, поэтому давайте скомбинируем В1А2 с СЗ, для того чтобы получить в итоге СЗВ1А2 с D3. D3C3B1A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗаб(Л). ЗЗаЮ. ЗЗЬ(И). ЗЗЫ. ЗЗс(И). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34(Л). 34.2(Л). 34.3(H). 34.4. 34.12 Сейчас мы должны включить Al, С2, D1 и D2. D2 не комбинируется с С2, поэ- тому давайте скомбинируем ее с СЗВ2А1. 02СЗВ2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). ЗЗаб. ЗЗабСИ). 33а7. ЗЗа8(И). 33а9, ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И). ЗЗсКЛ). ЗЗс4(И). ЗЗсЗ. 34(Л). 34.2(H), 34.4. 34.12
В итоге закончим мы следующим путем: D1C1B1A1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9. ЗЗаЮ. ЗЗЬ(И). ЗЗЫ. ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34(И). 34.1. 34.12 У нас не было вариантов для путей D5-D8. Если бы у нас были варианты, как .и в случае D1-D4, выбор комбинаций основывался бы на нескольких критериях. Нам необходимо было бы учитывать прошлую историю ошибок, насколько труд- но было анализировать комбинацию (выберите сложную комбинацию, так как если у вас есть проблемы, то они могут быть и у программиста), как много иссле- дований мы должны были сделать для прояснения проблемы (выберите комбина- цию, требующую больших исследований). Также пришлось бы опираться на ин- туицию и знание образа работы ответственного программиста. В качестве упражнения закончите выбор пути от узла 34.12 к узлу 40. У нас есть восемь тестов вплоть до узла 34.12. Узел 34 13 добавит только один тест. Узел 36 не добавит никаких тестов (почему?). Узел 38 добавит два теста. Оставшиеся предикаты не нуждаются в тестировании. Таким образом, похоже, что мы можем добиться покрытия связи за 11 тестов. Так как я этого не делал, я могу ошибаться. Однако когда мы будем активизировать эти тесты, возможно, придется вернуться назад и добавить другие тесты. На рассмотренный пример выбора пути (изложенный выше) я потратил семь часов. Может быть, я более опытен, чем вы, но мне пришлось его объяснять. Предыдущий пример не труднее, чем кажется. Вам следует его выполнить при- мерно за то же самое время. 3.4.4. Активизация З.4.4.1. Основы Активизация. Поиск входных значений, при которых (в случае отсутствия в реа- лизации ошибок) в модели будет пройден выбранный путь. Большая часть тех процедур, которые описывались в предыдущем разделе, яв- лялись активизацией логики в моделях. Процедура активизации зависит от пре- дикатов, встречающихся в рассматриваемом пути. Если предикаты в большинстве своем логические, как это было в предыдущем разделе, тогда активизация и выбор пути осуществляются одновременно. Если предикаты в большинстве своем чис- ленные (то есть алгебраические), то данные процедуры различаются, что описы- вается в подразделе «Алгебраическая активизация». Знание приложения важнее знания алгоритма активизации. Знание того, что приложение будет делать в том или ином случае, существенно для определения набора путей, обеспечивающих полное покрытие, и входных значений для их ак- тивизации. Я уверен, что если бы мы были экспертами в области налогообложе- ния, нам было бы гораздо легче найти для предыдущего примера набор путей, обеспечивающих покрытие. Прежде чем вы потратите силы и время на активиза- цию, запустите простейшие тесты вашей модели и убедитесь, что она обеспечива- ет покрытие связей. После этого у вас останется совсем немного мудреных путей, требующих для активизации применения формальных методов.
Если при активизации пути возникли непреодолимые трудности, то они мо- гут объясняться одной из следующих причин: путь непроходим, модель содер- жит ошибки или спецификация содержит ошибки. Проверьте эти предположе- ния, прежде чем потратить массу времени на бесполезную работу. 3.4.4.2. Логическая активизация Ниже приведен обзор процедур, которые мы должны сделать для выбора (и акти- визации) пути. 1. Разбейте модель на сегменты, начинающиеся и заканчивающиеся на оди- ночном узле. В примере, приведенном в разделе 3.4.3 «Выбор путей тести- рования», такими сегментами были: 32-33а4, 33а4-33а6, 33аб-33а8, 33а8- ЗЗЬ, ЗЗЬ-ЗЗс, 33с-34, 34-34.12, 34.13-35,35-37, 37-38, 39-39.3, 39.3-40. 2. Исследуйте сегменты и предикаты в них на предмет корреляции преди- катов. Проводите проверку одновременно двух сегментов. Составьте спи- сок сегментов, содержащих коррелированные предикаты. Вот некоторые из таких коррелированных сегментов в примере: 32-33а4/34-34.12, 33а4- 33а6/34-34.12, 33а6-33а8/34-34.12, 33а8-33а 10/34-34.12, ЗЗЬ-ЗЗс/ЗЗс- 34, ЗЗс-34/34-34.12. 3. Для каждого сегмента выпишите все возможные отрезки пути, на которых сегмент не содержит циклов. 4. Выберите два любых сегмента с коррелированными предикатами, даже если они не соединены напрямую, начните с тех пар сегментов, которые со- держат идентичные предикаты. Вам нужна строгая корреляция. Например, сегмент, в котором задается условие, и следующий сегмент, в котором это условие проверяется. Сегмент ЗЗЬ-ЗЗс помечает графу 33b, впоследствии это проверяется в узле 34.3 сегмента 34-34 12. 5. Исключите методом от противного непроходимые пути. Установите значе- ние предиката в первом сегменте равным ИСТИНА и устраните все отрез- ки пути во втором сегменте, на которых коррелированный предикат прини- мает значение ЛОЖЬ. Затем положите значение первого предиката равным ЛОЖЬ и устраните все отрезки пути во втором сегменте, на которых кор- релированный предикат принимает значение ИСТИНА. Будьте, однако, внимательны, так как отрицание последовательности предикатов в виде A&B&C&D... эквивалентно логической сумме отрицаний этих предикатов, то есть НЕ А ИЛИ НЕ В ИЛИ НЕ С ИЛИ НЕ D... Используйте для уверен- ности в верности преобразований булеву алгебру. 6. Продолжайте выполнять операции, описанные в пункте 5, объединяя сег- менты и устраняя по ходу их комбинации. Таким образом, вы построи- те более длинные пути, содержащие коррелированные предикаты. При объединении сегментов (например, 33с-34/34-34 12) вы создаете более длинные сегменты, хотя и с меньшим числом возможных путей в каждом из них.
7. На данном этапе у вас уже есть набор больших сегментов, которые не кор- релируют друг с другом. Это означает, что вы можете выбрать отрезки пути в каждом из сегментов, которые не зависят от других сегментов. Выберите достаточное число путей в каждом сегменте, чтобы быть уверенным, что вы обеспечили покрытие связей внутри этих сегментов. 8. Объединяйте сегменты, комбинируя пути и выбирая имеющие смысл ком- бинации. Обратите внимание, что число тестов при этом не должно увели- читься. Например, сегмент А содержит 6 путей, а сегмент В — 10 путей. Это означает, что пара сегментов будет содержать 10 путей, а не 60. Поскольку сегменты некоррелированные, вы можете связать любой отрезок пути в сег- менте А с любым отрезком пути в сегменте В. 9. Продолжайте до тех пор, пока не получите набора путей, обеспечивающих покрытие. 10. Теперь мы можем перейти непосредственно к активизации. Следуйте вдоль пути и по достижении предиката определите входное условие, при кото- ром предикат принимает значение ИСТИНА пли ЛОЖЬ, в зависимости от требований пути. Вам, возможно, придется использовать некоторые ме- тоды из следующего раздела для осуществления этого, однако, как правило, для большинства логических предикатов и предикатов выбора, это должно быть просто, так как вы уже убедились в отсутствии противоречий на вы- бранном пути. 3.4.4.3. Алгебраическая активизация Интерпретация предиката. Предикат считается интерпретированным, если он выражен через входные значения. Интерпретация предиката зависит от выбора пути. Это означает, что мы можем получить эквивалентный предикат, следуя в вычислениях по определенному пути, ведущему к этому предикату. Примером в данном разделе служит расчет детализированных л ьгот в Бланке А, строке 29 (См. Приложение). Модель для этого вычисления приводится ниже. Это не полная модель — она содержит только узлы, находящиеся на пути, который мы активизируем. Переменные, начинающиеся с буквы А, относятся к бланку А или к строкам формы 1040. Переменные, начинающиеся с буквы W, относятся к про- цедуре расчета. 1 1.1 input AL4 1.1 1.2 Input AL9 1.2 1.3 Input AL14 1.3 1.4 input AL18 1.4 1.5 input AL19 1.5 1.6 input AL26 1.6 1.7 input AL27 17 1.8 input AL28 1.8 2 W1 = AL4 + AL9 + AL14 + AL18 + AL19 + AL26 + AL27 + AL28 2 2.1 input AL 13 2.1 2.2 input AL28g 2.23 W2= AL4 + AL13 + AL19 + AL28g 3 3.1 W3= W2-W1
W3 - AL4 + AL9 +AL14 + AL18 + AL19 + AL26 + AL27 + AL28 - (AL4 + AL13 + AL19 + AL28g) W3 = AL8 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g Зт4 46т6 rf-ЫЗ <—9 IF AL9 । ALII । AL18 ' AL26 । AL27 ' AL28-----АШ-----AL28g <-0 Второй предикат на последней не зачеркнутой строке — это интерпретирован- ный предикат. Сначала мы подставили входные значения, а затем выразили пре- дикат через них путем их подстановки в символьном виде. Нетрудно заметить, что спецификация в данном случае неверна. В ней гово- рится: «если результат равен нулю...», а должно быть: «если результат меньше или равен нулю...» Я зачеркнул последнюю строку, поскольку активизация у нас выполняется вдоль определенного пути. Мы будем рассматривать путь, определенный на стро- ке 10. Продолжим модель: 3.1 4 IF AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g > О 4 5 0.8 * W3 - 0.8 * (AL9 + AL14 + AL13 + AL26 + AL27 + AL28 - AL13 - AL28g) 5 6 input AL32 6 6.5 если раздельно Этот путь я решил выбрать для данного теста. 6-6—если совместно 6.5 7 W6- $55.900 6-6—7-----W6 $111.800 7 7.1 W7 = W5 - W6 = AL32 - 55.900 7 -.1—Н).6 if-W7 <—е 8 if W7> 0: if AL32 - 55.900 > 0 8 9 W7* 0.03- AL32* 0.03-1.667.00 9---9-4 4-AL32*-». 03 h667.00 <-0.8 * (ALO ' ALM— AL 18 AL26 AL27 । AL28 AL13 - AL28g) 9.2 if AL32* 0.03 -1.667.00 > 0.8 * (AL9 + ALM + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g) 9.2 9.5 WL9 - 0.8 * (AL9 + ALM + AL18 + AL26 + AL27 + AL28 - AL13 - AL 28g) 9.5 10 WL10 = AL4 + AL9 + ALM + AL18 + AL19 + AL26 + AL27 + AL28 - 0.8*(AL9 + ALM + AL18 + AL26 + AL27 + AL28 - ALII - AL28g) Ниже приведены интерпретированные предикаты, через которые проходит этот путь: AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g > 0 РАЗДЕЛЬНОЕ ЗАПОЛНЕНИЕ AL32 - 55.900 > 0 Это простой случай, поскольку все три предиката полностью независимы. Но так бывает далеко не всегда. Как правило, входные значения встречаются сра- зу в нескольких интерпретированных предикатах. Следует отметить, что здесь указаны далеко не все существующие условия. Дополнительные условия: все входные переменные должны быть больше или равны нулю. Строго говоря, вам следует записывать такую информацию, чтобы не забыть ее на следующем шаге активизации.
На следующем шаге активизации мы ищем набор входных значений, удовле- творяющих всем интерпретированным предикатам на заданном пути. В послед- нем примере это выполняется достаточно просто. AL9 + AL14 + AL18 + AL26 + AL27 + AL28 > AL13 + AL28g РАЗДЕЛЬНОЕ ЗАПОЛНЕНИЕ AL32 > 55.900 Если нам сильно не повезет, то придется решать систему уравнений для ак- тивизирующих величин. Уравнения в системе представляют собой интерпре- тированные предикаты. В большинстве случаев, однако, это просто вопрос пра- вильного выбора входных значений для первого интерпретированного предиката, подстановки их в последующих предикатах и упрощения по мере продвижения. Предположим, например, что у нас есть следующий набор интерпретированных предикатов (это не относится к нашей модели) для выбранного пути: AL9 + AL14 + AL18 + AL26 + AL27 + AL32 > AL13 + AL28 AL9 + 0.05*AL14 > AL32 AL32 > 55.900 AL14 > AL18 Обратите внимание, что я расположил неравенства так. что они направлены одинаково. Сначала установите значение любой из входных переменных таким, чтобы избавиться от одного уравнения. В данном случае это значение величины AL32, которую я положил равной $55,905. Затем подставьте это значение в другие выражения и получите следующий набор предикатов. AL9 + AL14 + AL18 + AL26 + AL27 + 55.905 > AL13 + AL28 AL9 + 0.05*AL14 > 55.905 55.905 > 55.900 AL14 > AL18 Мы можем положить значение AL14 большим, чем AL18, например, предста- вив его в виде AL14 = AL18+10. AL9 + AL18 + 10 + AL18 + AL26 + AL27 + 55.905 > AL13 + AL28 AL9 + 0.05*(AL18 + 10) > 55.905 55.905 > 55.900 AL14 = AL18 + 10 > AL18 Упрощаем и группируем члены: AL9 + 2*AL18 + AL26 + AL27 + 55.915 > AL13 + AL28 AL9 + 0.05*AL18 - 55.904.50 > 0 Складывая эти два выражения, получим: 2*AL9 + 2.05*AL18 + AL26 + AL27 +10.5 - AL13 - AL28 > 0 Мы свели все наши условия к одному выражению, слагаемые в котором можем выбирать по нашему усмотрению. После того как мы это проделали, подставля- ем выбранные значения в выражения для величин, от которых мы предваритель- но избавились (AL14, к примеру), и в результате получим набор согласованных входных значений, удовлетворяющих всем интерпретированным предикатам на заданном пути. Вот мой набор входных значений:
AL9 - 10 AL18 = 15 AL26 - 30 AL27 = 40 AL13 - 5 AL28 = 10 AL14 = AL18 + 10 = 25 AL32 = 55.900 В большинстве случаев вы можете выполнить активизацию, не прибегая к фор- мальному решению уравнений с использованием матриц и даже не подозревая о том, что можно использовать эту процедуру. Начните с простейших неравенств, где у вас есть наибольшая свобода выбора и выберите входные значения для них. Потом подставьте эти значения в другие неравенства и упростите. Используйте простейшую арифметику для исключения переменных, комбинируя выражения путем их сложения и вычитания. Если вы не можете обойтись простейшими подстановками и упрощениями, то, прежде чем потратить время и силы на инвертирование матриц, проверьте специ- фикации и свои предыдущие действия. Как правило, причины, толкающие вас на инвертирование матриц, кроются в ваших предыдущих ошибках и/или в ошибках, содержащихся в спецификации. Другой способ решения данной проблемы — поместить ваши неравенства и вы- ражения в электронную таблицу и использовать встроенные методы решения сис- тем уравнений для получения ответа. Например, инструменты для решения урав- нений в LOTUS-123 справятся с этим превосходно. Более того, они позволяют смешивать логические и алгебраические предикаты в одном наборе неравенств. 3.4.5. Предсказание итогов Следующим шагом в процессе проектирования теста является предсказание ито- гов для каждого из выбранных путей. Хотя вашим первым побуждением будет по- пытка сыграть роль компьютера и пройти по этим путям вручную, не спешите это делать. Во-первых, это может быть очень непростой задачей. Во-вторых, вы бу- дете пытаться заменить собой компьютер, а в этом еще никто из людей не преус- пел. Вы с большей вероятностью допустите ошибку в вашем предсказании итогов, чем программист в программе. Ниже приведено несколько более привлекатель- ных альтернативных вариантов. Существующие тесты. Около 80 % труда разработчиков программного обес- печения на сегодняшний день уходит на сопровождение программ. Большинство тестировщиков и программистов работает над модификацией уже существующе- го программного обеспечения. Это означает, что 95 процентов ваших тестов не меняется от версии к версии. Если вы будете так же тщательно контролировать конфигурацию своих тестов, как и конфигурацию программного обеспечения, то у вас будет оракул для большинства ваших тестов. Старые программы. Серьезное обновление не всегда влечет за собой соответс- твующие изменения в тестовом комплекте, поэтому старые программы могут ис- пользоваться в качестве оракула. Например, старая программа была написана для
MS DOS. Теперь требуется перенести ее на другие платформы. Хотя подобная пе- ределка программы может вести к полному ее переписыванию, старая программа является превосходным оракулом. Запустите на ней свои тесты для нахождения ожидаемых итогов. Предыдущие версии. Даже если код, который вы тестируете, был переписан, как правило, для большинства путей корректные итоги могут быть получены из предыдущих версий программы. В худшем случае могут быть внесены изменения в небольшое количество путей, однако разница в итогах тестов для старой и новой версий программы легко прогнозируется. Используйте итоги, полученные для предыдущей версии, как отправную точку для поиска итогов для соответствую- щих путей в новой версии. Прототипы и модельные программы. Вы можете построить прототип, до- статочно подробный для того, чтобы получить с его помощью корректные ито- ги [STAK89]. Хорошие прототипы, как правило, не лишены функциональности. Причина, по которой они не могут служить рабочей программой, кроется в том, что они или слишком медленные, или слишком большие, или просто не могут ра- ботать в заданной операционной среде. Если у вас нет детально проработанного прототипа, вы можете получить оракула, построив модельную программу. Например, если бы мне надо было написать программу для заполнения декларации о подоходном налоге, я бы на- чал с того, что запрограммировал все формы в электронных таблицах, а алгеб- ру и логику — на каком-нибудь простом языке, например, BASIC. Это не то же самое, что писать код для реального продукта, поскольку вы не забиваете себе голову вещами, о которых должен заботиться программист, такими, как доступ к структурам данных, взаимодействие с операционной системой, ввод и вывод. В большинстве стандартных программных продуктов предусмотрено много ве- щей, не имеющих непосредственного отношения к прикладной задаче. Я не рас- полагаю точными цифрами, но полагаю, что менее 10 процентов программного кода имеют непосредственное отношение к прикладной задаче. Более того, эти 10 процентов кода зачастую являются наиболее простыми. Таким образом, пос- троение модельных программ и использование их в качестве оракула не лише- но смысла. Выбор простых вариантов. Иногда существует возможность выбрать входные значения так, чтобы они, с одной стороны, активизировали нужный нам путь, а с другой — упрощали вычисления. Например, установить все входные значения, кроме нескольких, равными пулю. В примере, приведенном выше, мы могли вы- полнить все условия при помощи подбора значений AL9. AL18 и AL13. Остальные входные величины мы могли положить равными нулю. Вы можете возразить, что ситуация, когда на входе может быть так много ну- лей маловероятна, но это плохой аргумент. В тестировании существует неписа- ное (и неудачное) правило, гласящее, что входные значения должны быть реалис- тичны. Реализм — это установка, мешающая хорошему тестированию. Реализм нужен для демонстраций, по он не является целью тестирования. Реалистичные тесты, хотя и кажутся убедительными, как правило, на поверку оказываются сла- быми, поскольку именно их программист с большой вероятностью выполнит сам.
Реализм не слишком хорош при поиске ошибок, а первоочередной задачей тести- рования является как раз поиск ошибок, а совсем не создание иллюзии доступнос- ти для простого человека. Если вы включили в свой допустимый набор входных значений такие мало- вероятные значения, как ноль, вы можете обнаружить, что предсказание ито- гов, интерпретация предикатов и последующая активизация становятся проще. Поскольку нереалистичные тесты, как правило, отличаются от тестов, проводи- мых программистами, они с большей вероятностью могут выявить ошибки. Конечная программа. Вы можете использовать конечную программу в качес- тве оракула, если вы в ней уверены. Обычно проще проверить правильность ито- га, чем вычислять его самому, подменяя собой компьютер. Это особенно касается случаев, когда вы можете вывести на печать и проверить промежуточные значе- ния величин. Под словом «уверены» я подразумеваю, что вы проводите анализ, подтверждающий корректность итогов. Если вы просто принимаете итоги как они есть, без проверки, вы, мягко говоря, ошибаетесь. 3.4.6. Проверка соответствия пути Вам необходимо проверять пути из-за угрозы возникновения случайной кор- ректности. Однако проверка пути при проведении тестирования черного ящи- ка — непростая задача, поскольку мы имеем дело с моделями поведения. Пути в тестировании — это пути через спецификации поведения, и нет никакой уве- ренности (и даже необходимости), что аналогичные пути существуют в реаль- ном программном обеспечении. Единственный способ убедиться в соответствии поведенческих путей в потоке управления, заключается в проверке корректнос- ти всех промежуточных вычислений, и особенно тех, которые обусловлены пре- дикатами потока управления. Если подобная проверка невозможна из-за отсутс- твия доступных промежуточных результатов обработки, то единственный способ их получить заключается во внедрении в программу (совместно с программис- тами) соответствующих логических операторов для проверки тестовых условий [ANDR81, CHEN78B], У вас нет необходимости проверять все вычисления. Найдите определение узла в начале этой главы: «один или более шагов обработки...». В большинс- тве приведенных моделей я, стремясь к наглядности, добавлял узлы и связи. Например, в модели на предыдущем рисунке узлы 34.1, 34.6, 34.8, 34.9, 34.10, 34.11, 34.14, и 34.15 несущественны. Граф на следующем рисунке содержит ту же самую информацию. Любая последовательность узлов, не являющихся объединяющими узлами или предикатами (узлами выбора), может быть заменена одним узлом с одной ис- ходящей связью. Такая сжатая модель будет проще, и ваша проверка сведется к проверке одного значения для каждой связи на выбранном пути, идентифициру- ющем данную связь. К примеру, можно проделать множество вычислений на пути 34.7-34.11-34.12, но все, что нам надо, это убедиться, что по данной связи прохо- дит одно единственное значение 3,175 — льготы женатого человека, заполняюще- го раздельную с женой налоговую декларацию.
Давайте посмотрим теперь на проблему проверки соответствия пути в пер- спективе. Проверка необходима из-за угрозы возникновения случайной коррект- ности. С другой стороны, поведенческое тестирование потока управления далеко не единственный метод, который вам придется использовать. Поэтому проверяй- те в пути все, что можете проверить. То есть если промежуточные элементы обра- ботки легко доступны и у вас есть инструменты тестирования для проверки соот- ветствия пути, программисты будут рады сотрудничеству с вами и помогут вам, используя эту защиту от ошибок. Другой приемлемый способ защиты от случайной корректности — это тестиро- вание нескольких вариантов для одного и того же пути. Мы к этому придем, рас- сматривая в дальнейшем другие методы тестирования, и особенно тестирование доменов. 3.5. Рассмотрение приложения 3.5.1. Индикаторы приложений Поведенческое тестирование потока управления применимо практически к лю- бой программе и эффективно для большинства приложений. Это фундаменталь- ный метод. Его используют обычно для тестирования относительно небольших программ или сегментов больших программ. Как будет видно из примеров, при- веденных ниже, он, скорее всего, будет эффективен для индивидуальных форм ВНС, но использовать его для тестирования всего пакета налоговых документов было бы затруднительно. Эти трудности объясняются тем, что модель получает- ся слишком громоздкой, а, следовательно, выбор пути и активизация настолько сложны, что результат не оправдывает затраченных усилий.
3.5.2. Предположения об ошибках Причиной большинства ошибок в программе могут являться ошибки потока управления, и, следовательно, возникающее при этом аномальное поведение мо- жет быть обнаружено путем тестирования потока управления. Однако основное предположение об ошибках, на поиск которых направлено тестирование потока управления, — это влияние ошибок на предикаты потока управления или то, что поток управления сам по себе неправилен. В качестве примера можно привес- ти ошибку в вычислении элемента, который в дальнейшем будет использоваться как часть предиката потока управления, например, использование >= вместо <. Примером грубой ошибки в потоке управления является ошибочное соединение узла 34.4 с узлом 34.14 вместо 34.12. Подобные грубые ошибки в потоке управле- ния сейчас встречаются довольно редко благодаря использованию языков струк- турного программирования. В старом программном обеспечении, написанном на языке COBOL, или, скажем, ассемблере, подобные ошибки встречаются значи- тельно чаще. Ошибки в вычислениях, не влияющие на поток управления, также можно ис- кать с помощью рассматриваемого метода, однако для этих целей существуют луч- шие методы. Тестирование доменов (см. глава 7) и тестирование потоков данных (см. глава 5) более эффективны при поиске подобных ошибок. 3.5.3. Ограничения и предостережения Ниже приведены некоторые ограничения и предостережения. 1. Вам не имеет смысла заниматься поиском отсутствующих требований, за исключением, конечно, того случая, когда ваша модель включает в себя эти требования, а программа — нет. 2. Вероятность того, что вы обнаружите неуместные или побочные характе- ристики, отсутствующие в требованиях, но присутствующие в программе, мала. 3. Чем лучше программист выполнил свою работу по тестированию модуля, тем менее вероятно, что данный метод обнаружит новые ошибки, например, если именно этот метод использовался при тестировании модуля (неплохая идея). 4. У вас мало шансов найти пропущенные пути и характеристики в программе, если программа и модель, на которой основывался тест, были написаны од- ним человеком. Если вы программист и используете этот метод для тести- рования своего собственного программного обеспечения, то неверное пред- ставление, которое привело в итоге к потере путей и характеристик в вашей программе, может остаться у вас в голове и когда вы проектируете тесты. Если тесты разрабатывает кто-то другой, вероятность одинаковых ошибок уменьшается, хотя и за счет увеличения затраченных усилий.
5. Для устранения хотя и небольшой, но все же существующей угрозы возник- новения случайной корректности вам надо проверить все промежуточные вычисления и значения предикатов. 6. Ваши тесты не лучше вашего оракула. 3.5.4. Автоматизация и инструментальные средства На момент написания этой книги не существовало коммерческих инструментов, предназначенных для работы с поведенческим тестированием потока управления, однако большое количество инструментов поддерживает структурное тестирова- ние потока управления. Вы можете использовать эти инструменты, запрограм- мировав ваши модели на поддерживаемых языках, таких как С, Pascal или Basic [DAIC93, GERH88, SCHI69, WARN64J. Это не будет потерей времени или избы- точным программированием. Работа, затраченная на создание достаточно деталь- ной графической модели, — это большая часть всей работы по представлению по- луформальной модели в виде программы. Причина, по которой программирование модели не является избыточным, и, конечно, отличается от программирования реального продукта, заключается в том, что вы не забиваете себе голову практическими вещами, такими как доступ к базам данных, взаимодействие с операционной системой, ввод и вывод, вопросы окружения и многим другим, порождающим реальные ошибки. В модельной про- грамме могут отсутствовать детали, она не обязана работать на какой-то конкрет- ной платформе, ей не обязательно быть производительной, и, что самое главное, она не должна быть интегрирована с другими частями продукта. Как используется модель? Вовсе не для запуска тостов реальной программы. Именно программа должна быть протестирована, а не какая-то модель тестиров- щика. Это так! Тестирование модели отличается от тестирования реальной про- граммы, но его тоже надо проводить. Как вы собираетесь отлаживать свои тесты? Модель надо использовать как инструмент, помогающий вам разработать набор тестов, обеспечивающих покрытие, для выбора и активизации путей, в качестве оракула для реального программного обеспечения. Если вы построили действу- ющую модель, то вы можете применить к ней коммерческие инструменты тести- рования. А это значительно упростит вашу работу. 3.6. Резюме Поведенческое тестирование потока управления рассмотрено как фундаменталь- ная модель тестирования черного ящика. Она является основой для всех других методов тестирования, обсуждаемых в этой книге, и впоследствии я буду считать, что вы ее усвоили. Проектирование тестов начинается с создания поведенческой модели графа потока управления на основе документированных требований, таких как специ- фикация. Представление в виде списка, как правило, более удобно, чем рисунки графов, но маленькие графы помогают при проектировании модели.
Составные предикаты в модели следует устранять или заменять, например, эк- вивалентными графами, для того чтобы не прятать реальную сложность. Вместо графа при моделировании составных предикатов, состоящих из более чем трех компонентов, используйте таблицу истинности. Разбейте вашу модель на отрезки, которые начинаются и заканчиваются оди- ночным узлом, и отметьте взаимную корреляцию предикатов во всех сегментах. Постройте ваши тестовые пути, комбинируя пути в сегментах и исключая непро- ходимые пути. Используйте противоречия между предикатами для вычеркивания отдельных комбинаций. Маловероятно, что эта методика приведет к непроходи- мым путям, которые будет невозможно активизировать. Выберите достаточное количество путей через модель, чтобы гарантировать полное покрытие связей. Не волнуйтесь, если тестов окажется слишком много. Начните с выбора очевидных путей, которые имеют прямое отношение к тре- бованиям, и посмотрите, не можете ли вы таким способом добиться покрытия. Возможно, вы получите не самые эффективные тесты, но это политически верное решение. Расширьте эти тесты, рассмотрев столько путей, сколько надо для сто- процентной гарантии покрытия связей. Активизируйте выбранные пути, интерпретируя предикаты вдоль пути в тер- минах входных величин. Интерпретированные предикаты дают набор условий или уравнений (в действительности неравенств), так что любое решение этого набора неравенств будет условием прохода по выбранному пути. Если активиза- ция не очевидна, то перед тем, как вы потратите много времени на решение урав- нений, проверьте, нет ли ошибок в спецификации или модели. Если условия все же сложны, рассмотрите вариант использования коммерческой программы, пред- назначенной для решения неравенств для активизации, такой как LOTUS 1-2-3. Алгебраический пакет может помочь с интерпретацией предикатов. Не забывайте о возможности случайной корректности и сотрудничайте с про- граммистами для получения промежуточных численных выводов, которые необ- ходимы для проверки пути. Дайте выражениям с предикатами высокий приори- тет, но не настаивайте больше чем на одном значении для каждой связи в графе. Продумайте программирование вашей модели с помощью реального языка программирования, используйте запрограммированную модель при проектирова- нии тестов. 3.7. Вопросы для самопроверки 1. Дайте определение следующих терминов: операция И, комплементарные сегменты пути, составной предикат, граф потока управления, коррелиро- ванные предикаты, независимые предикаты, объединяющий узел, логиче- ская модельная программа, логический предикат, НЕ, ИЛИ, предикат, ин- терпретация предиката, узел с предикатом, узел выбора, предикат выбора, активизировать, простой предикат, разделение транзакций, таблица истин- ности.
Во всех следующих примерах не надо моделировать побочные формы и ведо- мости, определенные в инструкциях ВНС. 2. Для бланка SE, 1994 и приведенного там же графа постройте граф потока управления, используя в качестве предикатов помечаемые графы. 3. Для бланка SE, 1994 замените в построенном вами графе все единичные со- ставные предикаты на эквивалентные последовательности простых преди- катов. 4. Для бланка SE, 1994 скомпонуйте один составной предикат, определяющий все условия, при которых надо заполнять короткую форму, и все условия, при которых надо заполнять длинную форму. 5. Постройте граф-модель потокауправления для формы 1040. Рассматривайте данные, приходящие из других форм или частей в качестве входов. Для каж- дого варианта постройте модель, выберете пути тестирования и спроекти- руйте тесты, используя обеспечение покрытия узлов и обеспечение покры- тия связей. Проверьте работу ваших тестов, используя в качестве оракула пакет программ для расчета налогов или модели в виде электронной таб- лицы. Если вы используете программу для расчета налогов, вам, возможно, придется брать входные значения из других форм. (1) строки 1-5, (2) стро- ки 6-22, (3) строки 32-40, (4) строки 41-46, (5) строки 47-53, (6) строки 54-60, (7) строки 61-65. 6. То же, что и в задаче 5 для формы 1040, бланка SE, короткая форма, строки 1-6, но включите в модель логику для определения того, может или не мо- жет быть использована короткая форма. 7. Форма 1040, бланк на строке 10. Полная форма. 8. Форма 1040, бланк на строке 20а, social security income (доход, подлежа- щий налогообложению по программе социального обеспечения). Полная форма. 9. Форма 1040, бланк на строке 34, dependent deductions (льготы иждивенца). Полная форма. 10. Постройте модель для строк 1-5 формы 1040, бланк на строке 26 (1994, Бланк Self-employed health insurance deductions (Льготы для частных пред- принимателей по программе страхования здоровья по старости)). 11. Найдите все пары коррелированных сегментов путей для примера в разделе 3.4.3. 12. Форма 2106, Employee business expenses (Расходы служащего по сделкам), часть II, разделы А, В, С. 13. Форма 2688, Application for Extension to File (Заявление о продлении сро- ка), строки 1-4. 14. Форма 2210, Недоплата налогов. Включает (а) Строка 1, (Ь) часть II, (с) часть III, (d) часть IV раздела В. Представьте, что вы можете исполь- зовать короткий метод (часть III), если вы не пометили графы 1b, 1с, или
Id. В любом случае выводы (если они есть) направляются на соответствую- щую строку формы 1040. Таким образом, вы можете не беспокоиться отно- сительно форм 1040А, 1040NR 1041, и т. д. 15. Форма 3903, часть I, Employee Moving Expenses (Расходы на поездки слу- жащего).
Тестирование циклов 4.1. Обзор Тестирование цикла — это эвристический метод, который следует использовать в сочетании со многими другими методами тестирования, поскольку опыт пока- зывает, что ошибки часто сопутствуют циклам. Методы, обсуждаемые в этой гла- ве, применяются в тех случаях, когда имеются циклы в таких графах как: граф по- тока управления, граф потока транзакций, или синтаксический граф. 4.2. Основные термины Внешние термины-, приложение, массив, компоновка, группа, С, оператор BREAK, сбор/воспроизведение данных, COBOL, код, компилятор, копировать, поврежде- ние данных, отказ, отладка, отрицательное приращение, конец файла, ввод (цик- ла), вычислять, выполнять, поле, файл, длина файла, FOR, GOTO, аппаратные сред- ства, эвристический, реализация, положительное приращение, инициализировать, внутренний цикл, целочисленный, итерация, ошибка границ в памяти, объедине- ние, модель, вложенный цикл, операционная система, внешний цикл, указатель, ошибка указателя, предусловие, процесс внутри цикла, обработка, программа, программист, программирование, язык программирования, случайный, запись, повторяющийся процесс, требование, время выполнения, поиск, программное обеспечение, сортировка, спецификация, язык структурного программирования, структурное программное обеспечение, завершать, передавать, истинное значе- ние, значение, переменная, WHILE. Внутренние термины, поведение, поведенческое тестирование, тестирование черного ящика, ошибка, граф потока управления, тестирование потока управле- ния, граф, модель на основе графа, цикл, связь, логический предикат, узел, имя 4 Зах. 770
узла, объект, исходящая связь, путь, предикат, отношение, действенный тест, предикат-переключатель, спецификация, структура, симптом, системное тестиро- вание, тестовый вариант, тестирование модуля. Цикл. Повторяющийся или итерационный процесс. Та часть модели-графа, ко- торая содержит цикл. То есть повторяющееся имя узла хотя бы на одном пути. Число повторений цикла. Число раз, которое повторяется цикл. При выходе из цикла не спутайте это число с конечным значением переменной управления цикла, если она существует (смотри ниже). Ошибочное принятие числа повторений цик- ла за конечное значение переменной управления цикла — распространенный ис- точник ошибок. Детерминированный цикл. Цикл, число итераций которого известно до того, как начнется выполнение цикла. Недетерминированный цикл. Цикл, число итераций которого неизвестно до того, как начнется выполнение цикла, или цикл, число итераций которого опреде- ляется или изменяется внутри цикла по ходу выполнения. Узел управления циклом. Узел с двумя и больше исходящими связями: для од- ной связи цикл будет выполняться, а для другой не будет. На рисунке узел управ- ления циклом отмечен как «20». 10 20 Узел выхода из цикли. Узел, который представляет предикат по крайней мере с одним значением, вызывающим отмену выполнения цикла. Цикл может, к несчас- тью, иметь более одного узла выхода. Узел 20 в голько что приведенной модели — узел выхода из цикла. Узел входа в цикл. Узел, через который происходит вход в цикл. Цикл может иметь более одного узла входа. Узел 10 на предыдущем рисунке — это узел входа в цикл. Предикат управления циклом. Предикат в узле управления циклом, значение которого определяет, будет цикл выполняться или нет. Переменная управления циклом. Любая переменная в предикате управления циклом, значение которой влияет на (истинное) значение предиката управления циклом — что определяет, будет цикл выполняться или нет. Цикл с предусловием. Цикл, в котором предикат управления циклом вычисляет- ся до того как выполняется какая-либо обработка внутри цикла. На рисунке узел управления циклом — это узел 20, а между узлами 10 и 20 нет никакой обработки. Вся обработка происходит на связи 20-10, так что это цикл с предусловием. Обработка Нет обработки
Цикл с постусловием. Цикл, в котором предикат управления циклом вычисля- ется после обработки. В циклах с постусловием обработка выполняется по мень- шей мере один раз. Нет обработки Цикл со смешанной проверкой. Цикл, в котором обработка происходит и до, и после того, как вычислен предикат управления циклом1. Вложенные циклы. Два или более циклов — вложенные, ес пи один полностью содержится в другом. На следующем рисунке цикл 10-20-10 является вложен- ным по отношению к циклу 5-25-5. 4.3. Отношения и модель 4.3.1. Основы В этом разделе мы используем язык программирования, так что может показаться, что мы говорим о программах. Однако мы говорим не только о программах или о циклах, которые могут находиться или не находиться внутри них. Тестирование черного ящика касается поведения, а не структуры. Наши модели — это модели поведения, и соответствующие циклы могут существовать или не существовать в тестируемом программном обеспечении. Если вы будете смотреть на программное обеспечение с чересчур близкого расстояния, пытаясь разобраться, с каким видом цикла вы столкнулись, вы можете допустить ту же ошибку в своей модели, что и программист в коде. 1 Пусть вас не сбивают с толку языки программирования и семантика конструкций типа опера- юров FOR и WHILE. Почти любая комбинация детерминировапных/недетерминированных циклов с проверкой до/после/смешапной может быть создана с помощью почти любой логической структуры. Смотрите упражнения в конце главы.
Вы заметите, что в нижеперечисленных моделях циклов я не использую кон- струкции структурного программирования, такие как FOR или WHILE, а использую вместо них явные предикаты и GOTO для данных модельных циклов. Мы имеем дело с моделями, а не с кодом. Я не ратую за отбрасывание конструкций FOR и WHILE в пользу GOTO. Я не использую структурные конструкции циклов в моделях, пос- кольку они зависят от языка, в котором реализованы, и в некоторых случаях даже от специфического компилятора для данного языка. Это особенно справедливо для проблем с циклами со смешанной проверкой. И именно это приводит к ошиб- кам циклов в коде и дизайне теста. Отношение между узлами в данных моделях — предшествует. Однако я осо- знанно не буду говорить ничего конкретного об оставшейся части модели. Здесь примеры будут приводиться для моделей потока управления, но тестирование цикла применяется и ко многим другим моделям (в том числе к тестированию синтаксиса), в которых, несмотря на то, что объекты и отношения различны, при- нципы тестирования остаются теми же. 4.3.2. Детерминированные циклы В детерминированных циклах число повторений цикла известно до того, как бу- дет выполняться первый оператор внутри цикла, и внутри цикла нет процесса, ко- торый вызвал бы изменение этого числа. 20 30 loop_control - 0. птах = 10 30 40 loop_process 40 30 loop_control =< птах. loop_control = loop_control + 1 50 loop_control > птах 50 продолжить оставшуюся часть модели Это пример цикла с постусловием. Предполагается, что переменная управле- ния циклом loop control не меняется процессом loop process на связи 30-40. Она может использоваться процессом loop process, но этот процесс саму ее не меняет. Узел 20 — входной узел цикла. Узел 40 — выходной узел цикла и вместе с тем узел управления циклом. Несмотря на то, что я использовал простое положительное приращение (loop_control = loop_control +1). можно использовать практически любую функцию, в том числе и отрицательное приращение, приращение на вели- чину т, или даже некоторую функцию от loop control. Переменной управления циклом здесь является loop_control, чье максималь- ное значение равно 10. Однако обработка будет выполнена И раз. Ниже дан при- мер детерминированного цикла с предусловием. 20 30 loop_control - 1. птах = 10 30 50 loop_control > птах 40 loop_control < = птах 40 30 loop_process. loop_control = loop_control + 1 50 продолжать оставшуюся часть модели Следующий пример — пример цикла со смешанной проверкой, поскольку об- работка цикла происходит и до, и после выходного узла цикла. 20 25 loop_control = 1. птах = 10 25 30 A_processing
30 50 loop_control > птах 40 loop_control > птах 40 25 B_processing, loop_control = loop_control + 1 50 продолжить оставшуюся часть модели В этой модели на каждом шаге обязательно выполняется A processing. На по- следнем шаге выполнения, однако, обрабатываемый объект минует B_process1ng. Заметьте, что значение переменной управления циклом, loopcontrol, различно для процессов А и В. Циклов со смешанной проверкой следует избегать в специ- фикациях, моделях и программном обеспечении, так как они уязвимы для оши- бок. В языках структурного программирования смешанные циклы не могут быть созданы случайно, перед их применением программисту следует хорошенько по- думать. Один из аргументов в пользу использования структурированных цик- лов — уход от ошибок, связанных со смешанными циклами. При построении мо- делей старайтесь использовать явные циклы с постусловием и предусловием, а циклы со смешанной проверкой применяйте только в тех случаях, когда они не- обходимы для точного моделирования требований. Если цикл со смешанной про- веркой необходим, то он должен быть тщательно протестирован из-за повышен- ной вероятности наличия ошибок. Поскольку в детерминированных циклах заранее известно число повторов, циклические процессы с их использованием надо конструировать во всех следу- ющих случаях: копирование файла с известным числом записей, обработка п пла- тежных чеков, добавление колонки чисел, заполнение массива числами, передача файла известной длины. 4.3.3. Недетерминированные циклы Недетерминированные циклы отличаются от детерминированных тем, что коли- чество проходов цикла неизвестно до его старта. Такое может произойти вследс- твие трех основных причин: это число неизвестно, обработка внутри цикла меняет переменную управления циклом (если она существует), внутри цикла обнаруже- но условие, вызывающее преждевременное прекращение цикла. 20 30 читать следующую запись 30 40 обработать запись 40 20 Не Конец Файла (КФ) 50 КФ 50 продолжить оставшуюся часть модели В вышеприведенном коде мы не знаем, как много записей имеет файл, следо- вательно, процесс будет продолжаться, пока не будет достигнута запись КФ. Этот пример уязвим в силу нескольких причин. Если файл содержит только запись КФ, тогда эта запись будет обработана с возможными пагубными последствиями. Другое слабое место проявляется в случае, если файл не содержит записей, даже записи КФ. Если программа точно реализует данную модель, с такими файлами цикл будет выполняться бесконечно. 20 30 loop_control = 1. птах = 10 30 50 loop_control > птах 40 loop_control < = птах
40 45 обработка цикла 45 46 loop_control = loop_control + INT(3*RAND) 46 30 loop_control = loop_control + 1 50 продолжить оставшуюся часть модели При обработке перехода 45-46 вышеприведенной модели из loop control каж- дый раз вычитается случайное число от 0 до 2. Я выбрал этот очевидный при- мер, но цели можно достигнуть и без использования случайных чисел. Дело в том, что мы не можем определить, когда выполнение этого цикла будет закончено, — если вообще когда-нибудь будет. Несмотря на то, что может показаться, будто кон- струкция детерминирована, она, тем не менее, является недетерминированной. 20 30 loop_control = 1. птах = 10 30 50 loop_control > птах 40 loop_control < = птах 40 45 обработка цикла 45 47 значение поля = 17 46 значение поля * 17 46 30 loop_control = loop_control + 1 47 30 loop_control = птах + 1 50 продолжить оставшуюся часть модели Несмотря на то, что вышеприведенный фрагмент имеет вид детерминирован- ного цикла, он таким не является. Предикат в узле 45 проверяет величину опреде- ленного поля. Если эта величина равна 17, loop control принимает значение, вы- зывающее прекращение выполнения цикла. Если значение поля не равно 17, цикл последовательно выполняется до значения птах. В последнем случае цикл явля- ется детерминированным. Мне не обязательно изменять переменную управления циклом, чтобы добиться этого. Например, следующий фрагмент делает то же са- мое без изменения переменной управления циклом. 20 30 loop_control = 1. птах = 10 30 50 loop_control > птах 40 loop_control < = птах 40 45 обработка цикла 45 50 Значение поля = 17 46 Значение поля * 17 46 30 loop_control = loop_control + 1 50 продолжить оставшуюся часть модели Процессы с недетерминированными циклами включают: сортировку п запи- сей, поиск файла, получение файла по каналу связи, решение системы уравнений, объединение двух файлов. Различие между детерминированным и недетерминированным циклами чрез- вычайно важно. Недетерминированные циклы, как правило, чаще содержат ошиб- ки по сравнению с детерминированными и потому должны более тщательно тести- роваться. В языках структурного программирования конструкция FOR (например, FOR I = 1 to loopmax DO ...) предназначена для детерминированных циклов. Наоборот, конструкция WHILE ... DO предназначена для недетерминированных циклов. Цикл FOR имеет явную переменную управления циклом, цикл WHILE не имеет. Поскольку циклы FOR могут быть недетерминированными, а циклы WHILE детерминированны- ми, большинство программистов полагает, что выбор между ними — вопрос сти-
листики. Это приводит к ошибкам, в которых недетерминированные процессы ре- ализованы при помощи детерминированных конструкций, а детерминированные — при помощи недетерминированных. И тот и другой случай сбивают с толку, повы- шают вероятность ошибки и потому перспективны для выявления. 4.3.4. Вложенные циклы Вложенные циклы являются проблемными (то есть часто содержат ошибки). Они содержат, конечно, обычные ошибки, которые можно ожидать в единичном цик- ле (например, потерю первого варианта, слишком раннее прекращение, слишком позднее прекращение, бесконечное выполнение), но также и ошибки, возника- ющие в результате одновременного достижения условий прекращения в обоих циклах. Например, рассмотрим следующий фрагмент кода. 20 30 outer_loop_control = 1. outermax = 10 30 40 inner_loop_control = 1. innermax = 100 40 45 обработка внутреннего цикла 45 30 inner_loop_control < innermax. inner_loop_control = inner_loop_control + 1 50 inner_loop_control > - innermax 50 55 обработка внешнего цикла 55 20 outer_loop_count < outermax. outer_loop_control = outer_loop_control + 1 60 outer_loop count > - outermax 60 продолжить оставшуюся часть модели Что здесь произойдет при outer loop control = 13 и inner loop control = 100, а также при близких им значениях? 4.3.5. Неструктурированные (ужасные) циклы Ужасные циклы имеют место в случаях, когда происходит прыжок (переход) из се- редины или прыжок в середину цикла. На следующем рисунке представлена эта печально известная структура, по- скольку в пей присутствуют оба типа переходов. Связь 30-10 является прыж- ком из цикла 20-30-40-20, в то время как связь 40-20 представляет собой ска- чок в цикл 10-20-30-10. Циклы со смешанной проверкой не слишком ужасны, поскольку в них происходит скачок из середины цикла. Другая проблема циклов со смешанной проверкой заключается в том, что входной узел цикла для первой итерации отличается от входных узлов цикла для последующих итераций. Программисты должны стараться избегать создания ужасных циклов на язы- ках структурного программирования, но такие циклы часто встречаются в старом
программном обеспечении, написанном на языке ассемблера и более старых язы- ках программирования. Для ужасных циклов нет хороших тестов. Как вы управитесь с ними, зависит от того, откуда они взялись. Если они следствие способа, с помощью которого вы построили модель, тогда смоделируйте ее заново, используя структурированные циклы. Ужасные циклы могут быть корректной моделью поведения приложения, особенно если, как в случае тестирования потока транзакций, вы создаете модель человеческого поведения. Например, если вы моделируете поведение человека, набирающего междугородний телефонный номер, естественно использовать цикл для набора цифр. Междугородний телефонный вызов требует набора И цифр. Тогда вы создаете следующий модельный цикл. 10 20 dig1t_count = 0. d1g1t_max - 11 20 30 d1g-it_count < = dlgitjnax. digitjrount = cigit_count + 1 50 digit_count > dlgitjnax. выйти из цикла 30 20 набор цифры 50 продолжить дальше модель Люди не могут и не будут вести себя структурно. Например, они могут сразу выйти из цикла, поняв, что совершили ошибку при наборе номера. 10 20 digit_count = 0. dlgitjnax = 11 20 30 digit_count < = dlgitjnax. digit_coLnt = digit_count + 1 50 digit_count > dlgitjnax. выйти из цикла 30 40 набор цифры 40 20 цифра набрана успешно 10 цифра не набрана, трубка вешается и номер набирается заново 50 продолжить дальше модель Если скверная структура цикла должным образом моделирует ситуацию, то- гда у вас нет другого выбора, кроме как смоделировать ее именно так. Однако вы должны протестировать подобные циклы более тщательно, чем обычно, посколь- ку такие ситуации чаще подвержены неправильной реализации, особенно в спе- циальных случаях, порождающих ужасные циклы. 4.4. Методы 4.4.1. Критические тестовые значения Рассмотрим общую детерминированную модель цикла. 10 20 loop_control = startval. 1 termax - upperval 20 30 loop_control > 1 termax 40 loop_control < = 1 termax 30 20 loop process. loop_control = loop_control + increval 40 продолжить оставшуюся часть модели Этот цикл определяется тремя значениями: startval — начальное значение переменной управления циклом. upperval — конечное значение переменной управления циклом.
increval — величина, на которую переменная управления циклом будет возрас- тать при каждом прохождении цикла. Критические тестовые значения — комбинация величин этих трех чисел, ко- торые, как показывает опыт, особенно часто вызывают ошибки, плюс, в добавле- ние к ним, нормальный или типичный вариант. Мы приводим тестовые варианты в самом общем виде. Специфические особенности для разных типов циклов будут обсуждаться в последующих разделах. Обход. Любой набор величин, вызывающий немедленный выход из цикла. Один проход. Величины, приводящие к тому, что цикл выполняется ровно один раз. Два прохода. Величины, приводящие к тому, что цикл выполняется ровно два раза. Типичное число проходов. Типичное число итераций. Максимум'. Максимальное число разрешенных итераций. Мах + 1. На единицу больше разрешенного максимума. Мах - 1. На единицу меньше разрешенного максимума. Мт. Заданный минимум. Min - 1. На единицу меньше заданного минимума. Ноль. Обсуждается ниже. Отрицательное число проходов. Обсуждается ниже. Заметьте, мы говорим о числе раз повторения цикла, а не о значениях перемен- ной управления циклом (если она существует). Например, в цикле FOR I - 0 to 8 STEP 2 исходное значение переменной управления циклом I равно 0, но цикл будет выполнен не девять раз, а только пять, потому что переменная управления циклом при каждом прохождении цикла увеличивается на два. Многие из упомянутых вариантов могут перекрываться. Например, если зна- чение минимума равно 0, тогда имеют место следующие тождества: Min - 1 - Отрицательное число проходов Min = Обход Min + 1 = Один проход Аналогично, если значение минимума равно 1: Min - 1 - Обход Min = Один проход Min + 1 - Два прохода Вариант нуля может оказаться эквивалентным варианту обхода. Обычно вмес- то 11 только что перечисленных тестов разрабатываются только 7. Некоторые из этих вариантов, такие как обход, могут перекрываться с тестом, созданным на ос- нове покрытия связей. В дополнение к тестированию 11 общих ситуаций в старом программном обес- печении (например, программном обеспечении, написанном на языке ассемблер), возможно, имеет смысл протестировать особые значения числа итераций, такие как степени двойки и близкие к ним значения: 255, 256, 257, 65535, 65536 и 65537. Но не теряйте времени на особые значения, связанные с параметрами аппаратных средств, такими как байт или длина слова в таком современном языке программи-
рования, как С — за исключением, конечно, того случая, когда вы проверяете реа- лизацию и видите, что имеете дело с низкоуровневым программированием. 4.4.2. Детерминированные циклы Мы обрабатываем выплату жалования. Программное обеспечение должно обра- батывать минимум одного служащего и максимум 20 000 служащих. Используя рассмотренные выше установки, мы сразу получим следующие тестовые вари- анты: Обход. Нет служащих. Один проход. Один служащий. Два прохода. Два служащих. Типичное число проходов. 700 служащих. Максимум. 20 000 служащих. Мах + 1. 20 001 служащий. Мах - 1. 19 999 служащих. Min. Один служащий (избыточный вариант). Min - 1. Нет служащих (избыточный вариант). Ноль. Нет служащих (избыточный вариант). Отрицательное число проходов. Отрицательное число служащих? Некоторые из этих вариантов заслуживают более подробного обсуждения. Обход: нет служащих. Согласно требованиям, программное обеспечение не предполагает обработку этого случая. Но что оно сделает? Может ли этот вариант, хотя он и не имеет смысла, возникнуть? Скажем, пакет программ используется для создания платежных ведомостей для многих разных организаций. Он обра- батывает их по очереди (вложенный цикл с внутренним циклом для служащих и внешним циклом для организаций). Новый клиент добавляется в очередь для об- работки недельной платежной ведомости, но мы пока что не получили данных со- трудников. Мы не ждем, что программное обеспечение «обработает» заработную плату для сотрудников-фантомов. И наоборот, мы не ждем, что программа начнет печатать бесконечное число чеков по $0.00 для имя. фамилия. Мы тестируем. Нам платят не за привлекательность, пе за справедливость и даже не за благоразумие. Если вообще возможно смоделировать ситуацию, мы должны сделать это и ожидать от программного обеспечения, что оно поведет себя разумно, например, скажет нам, что «название организации не будет обработано». При проведении тестирования мы подозреваем (и надеемся), что при обработке платежной ведомости какой-либо другой организации не будет учтен один из слу- жащих или ведомость будет целиком пропущена. Один проход: один служащий. Ищем пустой дополнительный платежный чек, продублированный платежный чек или недостаток одного чека для следующей организации. Два прохода: два служащих. Часто действенно, в особенности для «смешанных» циклов. Ищите дублированную инициализацию циклов, потерю второго служа- щего, два платежных чека для второго служащего или какую-нибудь ошибку для следующей организации.
Типичное число проходов. Неперспективно для обнаружения ошибок, но если вы это не проделаете, то, конечно, ваше тестирование может быть подвергну- то критике. Несмотря на то, что это редко бывает эффективно для обнаружения ошибок, это политически мудро. Максимум. Все тестовые варианты, которые ориентированы на максимумы, мо- гут потребовать больших затрат, в особенности для вложенных циклов. Например, 20 000 служащих и 1000 организаций означают 20 000 000 платежных чеков. Даже с компьютерами это накладно. Дело не в том, что числа 20 000 и 1000 — это какие-то особенные числа, вызывающие ошибки. Дело в том, что достигнуты мак- симумы, вне зависимости от их значений. Если программисты предвидят возмож- ные проблемы с тестированием, они встроят возможность изменить эти макси- мальные значения для тестирования, которое в большинстве случаев может быть проведено для 20 сотрудников и 10 организаций. Если возможность тестирования не была целью проектирования, у вас нет другого выбора, кроме как протестиро- вать эти экстремальные значения, по крайней мере, один раз. Но проделайте это, скажем, для 20 000 служащих и только одной организации, и 1000 организаций, в каждой из которой всего несколько служащих. Максимум плюс 1. Ситуация, аналогичная случаю обхода. Мы не ждем, что программа обработает больше, чем заданный максимум, нс поскольку такая си- туация может случайно возникнуть, мы хотим быть уверены, что это не приве- дет к сбою и файлы не будут повреждены. Ищите ситуацию, koi да в компании X работает 20 001 служащий, в порядке обработки компания Y следует за ком- панией X и первый служащий в компании Y получает платежный чек со счета компании X. Отрицательное число проходов. Если число служащих может быть введено с клавиатуры, скажем, для того, чтобы начать обработку, тогда этот случай мо- жет быть потенциально продуктивным. Если вы можете всеми правдами или неправдами реализовать этот случай, попробуйте это сделать, и посмотрите, от- клонит ли программа такое входное значение. Не обманывайте себя тем, что этот случай действительно будет отклонен только потому, что вам так сказали. Например, из-за ошибки ввода заявлено, что в компании X работает —10 слу- жащих. Даже если этот случай, как и ожидалось, будет отклонен, то первые 10 платежных чеков для следующей в очереди организации Y могут быть не обра- ботаны. Мы имеем дело с ошибками, которые ведут к произвольному или бес- смысленному поведению. Таким образом, всегда, когда это возможно, имеет смысл использовать произвольные и бессмысленные тестовые варианты. 4.4.3. Недетерминированные циклы Мы ищем в файле неизвестной длины специфическую запись, которая может на- ходиться в любом месте файла или, если уж на то пошло, может вообще не содер- жаться в файле. Здесь мы имеем две проблемы; с размером файла и с тем местом в файле, где может быть найдена искомая запись. Два предиката управляют по- ведением этого цикла: предикат, управляющий получением и проверкой следую- щей записи, и предикат, вызывающий остановку выполнения цикла в случае, ког-
да искомая запись найдена. Сначала мы обсудим вопрос о размере файла, а затем вопрос о месте в файле, где найдена запись. Обход. Файл без записей. Этот вариант также является нулевым. Поскольку в файле нет записей, искомая запись не может быть найдена. Один проход. Файл с одной записью. 1. Информация найдена: искомая запись и есть первая запись. 2. Информация не найдена: искомой записи нет в файле. Два прохода. Файл с двумя записями. 3. Информация найдена в первой записи. 4. Информация найдена во второй записи. 5. Информация не найдена. Типичное число проходов. Файл с 10 записями*. Информация найдена в первой записи. 1. Информация найдена в записи 6. 2. Информация найдена в записи 9. 3. Информация найдена в записи 10. 4. Информация не найдена. Максимум - 1. Например, мы можем положить максимальное число записей в тестируемом файле равным 50. 1. Информация найдена в записи 48. 2. Информация найдена в записи 49. 3. Информация не найдена. Максимум. Файл, состоящий из 50 записей 1. Информация найдена в записи 49. 2. Информация найдена в записи 50. 3. Информация не найдена. Максимум + 1. Файл, состоящий из 51 записи Информация найдена в записи 49. 4. Информация найдена в записи 50. 5. Информация найдена в записи 51. 6. Информация не найдена. 1 Я выбрал 10 записей, поскольку теория и опыт говорят, что значения 1,2,3,4 и 5 могут приводить к различным моделям поведения. Поскольку 5 - 1 = 4 не является общим вариантом, 5 пропущено. Поскольку 6 - 1 - 5 — это первый общий вариант, 5 не является хорошим значением. Первое хорошее общее значение — это, возможно, 7. Но степени двойки и числа, близкие им (7, 8, 9), могут быть про- блемными, так что 10 — это первое действительно хорошее типичное значение.
Вот мои аргументы в пользу тестового варианта МАХ + 1. Мы не предполагали, что программное обеспечение будет обрабатывать файлы, в которых более 51 за- писи. Если цикл действительно недетерминированный, тогда этот факт неизвес- тен нам до того, как процесс закончится. То есть длина файла становится извест- на только после обнаружения записи КФ (конец файла). Если это действительно так, тогда не существует способа запретить обработку файла с 51 записью. В про- тивном случае, если чрезмерно длинный файл отвергается до того, как начнется обработка, тогда длина файла должна быть известна и цикл поиска не является по-настоящему недетерминированным. Неизвестна только точка, в которой про- цесс выйдет из цикла. Как много рассмотренных вариантов вы испробуете, зави- сит от того, что делает цикл недетерминированным. 1. Величина максимума неизвестна и не может быть найдена. В этом случае ничего не препятствует достижению максимального значения и вам обяза- тельно следует попробовать МАХ + 1. 2. Досрочное прекращение. У нас есть однозначно детерминированный цикл, выполнение которого может быть досрочно прервано (например, операто- ром BREAK в языке С), но где это произойдет, неизвестно. МАХ + 1 не имеет смысла, но непременно попробуйте найти искомые данные в последней за- писи. 3. Обработка переменной управления. Это может происходить с детермини- рованными и недетерминированными циклами. Скажем, число записей было известно, и то, что мы хотели проделать, — это выборочная провер- ка одной из десяти записей, вместо того чтобы проверять каждую запись в файле. Это может быть реализовано увеличением переменной управления цикла на 10, но это приводит к выходу величины указателя за границу фай- ла. Тогда нам, безусловно, следует попробовать варианты МАХ + 1. 4.4.4. Вложенные циклы Вложенные циклы сначала должны быть протестированы как индивидуальные циклы. Задайте для внутреннего цикла типичное значение и протестируйте внеш- ний цикл для случаев критических значений. Затем измените процедуру на про- тивоположную, задайте для внешнего цикла типичное значение и прогоните внут- ренний цикл через критические тестовые варианты. Эти тесты должны выявить большинство ошибок, обычно попадающихся в одиночных, невложенных циклах. Проблема с вложенными циклами возникает, когда два или более вложенных цикла достигают критических значений одновременно — например, нулевых, мак- симальных, и так далее. Вы проектируете тестовые варианты путем перебора ком- бинаций критических значений. Это должно привести к 64 или большему числу тестовых вариантов, если вы строго следуете этому правилу. Отступите немного от этого и протестируйте по крайней мере комбинации обход/ноль, один, два и МАХ для внутреннего цикла и обход/ноль, один, два и МАХ для внешнего цик- ла. Это будет 16 случаев в дополнение к тестированию одиночных циклов — все- го 32 теста.
4.5. Рассмотрение приложения 4.5.1. Индикаторы приложений Каждый повторяющийся (циклический) процесс требует тестирования. Каждый граф с циклами должен быть протестирован, с возможным исключением графов для автоматов с конечным числом состояний1 (глава 9), потому что в этом слу- чае имеется слишком много циклов, и тестирования доменов (глава 7), где присут- ствие циклов делает метод неприменимым. 4.5.2. Предположения об ошибках Здесь нет особо глубоких предположений; только эмпирическое наблюдение, что повторяющимся процессам трудно корректно начаться и еще более трудно пра- вильно остановиться. Мы выполняем какие-то действия слишком много или слишком мало раз. Многие ошибки происходят также из-за того, что кто-то до- пускает существование определенных предусловий, хотя в действительности они не обязательны: например, что все файлы содержат хотя бы одну запись. 4.5.3. Ограничения и предостережения Ошибки циклов обычно обнаруживаются в низкоуровневом программном обес- печении и чаще всего имеют ограниченное влияние. Симптомы, как правило, вы- являются неподалеку от самой ошибки и одновременно с ней. Многие из этих ошибок будут обнаружены операционной системой или исполняемой резидент- ной частью компилятора, потому что они вызывают переполнение памяти, обна- ружимые ошибки указателя, чтение вне пределов файла и другую подобную че- пуху. Ошибки, обнаруженные путем тестирования цикла, не очень коварны и мы хотели бы надеяться, что программисты найдут и исправят их при низкоуровне- вом тестировании модулей, где они часто могут быть найдены при тестировании цикла. Не ожидайте очень многого от тестирования цикла для развитого программ- ного обеспечения. 4.5.4. Автоматизация и инструментальные средства Специальные инструменты на самом деле не нужны. Если вы используете тести- рование циклов как часть системного поведенческого тестирования, вы можете с успехом эксплуатировать систему покрытия/воспроизведения. Индивидуальные тесты циклов, особенно если они касаются файлов и вложенных циклов, могут быть трудны для реализации. Однажды реализовав и отладив типичный тесто- вый вариант для цикла, редактируйте его, изменяя входные значения для созда- ния других вариантов тестирования цикла, в особенности это касается комбини- рованных вариантов, необходимых для вложенных циклов. 1 На самом деле любых сильно связных графов.
4.6. Резюме Тестирование цикла — это эвристический метод, основанный на опыте, который программисты приобретают, сталкиваясь с ошибками в начале и конце циклов. Несмотря на то, что для пояснений в этой главе были использованы примеры с по- током управления, метод эффективен для большинства графовых моделей, име- ющих циклы (исключая сильно связные графы). Необходимые для тестирования значения основаны на числе повторений цикла: 0,1, 2, MIN - 1, MIN, MIN + 1, ти- пичное количество проходов, МАХ - 1, МАХ, и МАХ + 1, а также на комбинациях этих величин для вложенных циклов. 4.7. Вопросы для самопроверки 1. Дать определение следующих терминов: критические тестовые значения цикла, детерминированный цикл, ужасный цикл, число итераций цикла, цикл, обход цикла, узел управления циклом, предикат управления циклом, переменная управления циклом, узел входа в цикл, узел выхода из цикла, цикл со смешанной проверкой, вложенные циклы, недетерминированные циклы, цикл с проверкой до, цикл с проверкой после. 2. Рассмотрите шесть комбинаций циклов (детерминированных, недетерми- нированных) и (с проверкой до, после, со смешанной проверкой) в языке С. Придумайте примеры для каждой комбинации, используя следующие конс- трукции для создания циклов: WHILE, FOR, DO WHILE, IF/GOTO. Если комбинация невозможна, докажите это. 3. То же, что и задание 2, но для Паскаля, с использованием FOR-7O-DOWNTO, FOR- DO, REPEAT - UNTIL, WHILE, и всех прочих способов создания циклов. 4. В большинстве пакетов программ для подготовки налоговых документов имеется команда для вывода форм и бланков пользователя на печать. Если каждая форма рассматривается как объект, который следует распечатать, этот циклический процесс детерминированный или недетерминирован- ный? Обоснуйте ваш ответ. Если вы скажете ««детерминированный»», по- чему практичный человек может решить запрограммировать этот процесс с помощью недетерминированного цикла? Разработайте набор тестов для печати действующей декларации о доходах в вашей программе подготовки налоговых документов. 5. Классифицируйте как детерминированные или недетерминированные (по отношению к числу итераций цикла) следующие процессы: (а) проверка ор- фографии, (б) решение системы уравнений, (в) сортировка, (г) объединение, (д) сложение двух чисел, (е) извлечение квадратного корня, (ж) деление столбиком, (з) проведение переписи населения в Америке, (и) копирование файла, (к) копирование каталога, (л) копирование всего диска, (м) проверка диска на наличие ошибок, (н) загрузка файла, (о) подсчет числа пред- метов в коробке, (п) пересчет числа предметов в коробке, (р) проверка
ваших счетов, в предположении, что ни вы, ни банк не делали ошибок, (с) поэлементное умножение двух массивов, (т) поэлементное умножение двух матриц, (у) извлечение квадратного корня из 16-битного числа и обес- печение представления результата в виде 16-битного числа, (ф) вычисление X2 hsin-1 ABS((J2(ABS( 17 f е dx)))) , где х — 16-битное число и ре- о зультат необходимо представить в виде 16-битного числа, (х) удаление п символов из конца документа начиная с последнего и в обратном поряд- ке, (ц) добавление п символов в конец документа, (ч) удаление п символов из середины документа, когда известно, что документ содержит не меньше п символов. 6. Для каждого из детерминированных процессов из задания 5 укажите, ка- ковы практические последствия (например, в части уязвимости, расхода оперативной памяти и дискового пространства), которые могут возникнуть в результате реализации процесса в виде недетерминированного цикла. 7. Для каждого из недетерминированных процессов из задания 5, каковы практические последствия (например, в части уязвимости, расхода опера- тивной памяти и дискового пространства), которые могут возникнуть в ре- зультате реализации процесса в виде детерминированного цикла? 8. Какие из процессов в задании 5 имеют вложенные циклы и какая глубина их вложения? 9. Для каждого из процессов, проанализированных вами в заданиях 5,6, 7 и 8, создайте набор тестов циклов. 10. Смоделируйте часть 4 формы 2210 как граф потока управления с детерми- нированным циклом и протестируйте его соответствующим образом.
Тестирование потоков данных 5.1. Обзор Граф потока данных является характерной особенностью многих методов проек- тирования программного обеспечения и с успехом используется в проектирова- нии тестов. 5.2. Основные термины Внешние термины: добавить запись, алиас, приложение, массив, присваивать, ошибка, С, вычисление, дерево вызовов, CASE, закрывать, код, комментарий, срав- нивать, компилятор, вычисление, параллельный процесс, константа, ограничение, управление, копировать, число повторений, аварийный отказ, создавать, данные, отладочная программа, удалять, обозначать, диск, фиктивная переменная, динами- ческий вызов, выражение, извлекать, выборка (команды или данных из памяти), поле, файл, формула, функция, глобальные данные, остановка, аппаратные средс- тва, эвристический, иерархический, IF-THEN, IF-THEN-ELSE, сокрытие информации, инициализировать, вставлять, конкретизировать, итерировать, число повторе- ний, переход, редактор связей, размещение, логический, цикл, сопровождение, па- мять, адрес ячейки памяти, объединять, сообщение, перемещать, многозадачность, сеть, численный, имя объекта, объектно-ориентированное программирование, от- крывать, вывод, собственные данные, параллельный компьютер, раздел, PASCAL, указатель, обработка, программа, программист, программирование, язык про- граммирования, псевдокод, ОЗУ, запись, переименовывать, повторно использу- емый, время выполнения, поиск, упорядочение, совместно используемые данные, побочный эффект, программное обеспечение, сортировать, исходный код, элек- тронная таблица, оператор, хранить, структурный, символьный, синхронизация,
таблица, тестируемость, тестировщик, передавать, истинное значение, значение, переменная. Внутренние термины: поведенческое тестирование, слепота, тестирование вет- вей, случайная корректность, компонент, составной предикат, поток управления, граф потока управления, оборванная связь, детерминированный цикл, грязный тест, входной узел, выходной узел, модель с конечным числом состояний, граф, начальное состояние, входящая связь, интеграция, ввод, входной узел, покрытие связей, представление графа в виде списка связей, вес связи, цикл, тестирование цикла, модель, отрицательный тест, вложенный цикл, узел, покрытие узлов, вес узла, недетерминированный цикл, объект, оракул, итог, исходящая связь, узел вы- хода, путь, позитивный тест, предикат, интерпретация предиката, отношение, тре- бование, активизировать, простой предикат, спецификация, состояние, граф по- тока транзакций. Определение (объекта). Объект определяется в тех случаях, когда ему присваи- вается новое значение, он инициализируется, создается или конкретизируется. Не путайте имя объекта или адрес ячейки памяти, испол1.зующейся для хранения его значения, с различными возможными определениями этого объекта. Например, ячейка памяти XYZ используется для хранения переменной с именем SAM. SAM может принять несколько различных значений по ходу вычисления. Каждое из этих значений является определением SAM. Перегрузка. Имя переменной перегружено, если оно используется для обоз- начения различных определений переменной по ходу выполнения программы. В программировании считается, что выгода использования перегрузки заключа- ется в экономии памяти1, но в моделях тестирования перегрузка не дает никаких преимуществ, поскольку она только запутывает и ничего не экономит. Логический оператор. Оператор языка программирования, включающий пре- дикат, вычисляемый по ходу выполнения. Если предикат получает истинное зна- чение, обработка продолжается. Если предикат получает ложное значение, проис- ходит по крайней мере одно из следующего: управление передается обработчику логического выражения, выражение помечается как невыполненное, выполнение программы приостанавливается, управление передается отладочной программе. Логические выражения обычно проверяют соотношения между значениями пере- менных, такие как х > 17 или х + у = z. Выражения — мощный подсобный инстру- мент тестирования. В этой главе логические выражения в основном используются для проверки результатов вычислений. Использование для вычислений. Объект используется для вычислений [RAPP82], когда он применяется для расчета значения другого объекта. Например, в вы- ражении Y:=X + ZXnZ используются для вычисления Y, a Y — определяется. Аналогично, вХ: = X + Y, XhY используются для вычислений, и в то же время X (пере)определяется (здесь X — перегружено). 1 На самом деле при использовании оптимизирующего компилятора перегрузка не экономит па- мять. Она, наоборот, по всей вероятности, увеличивает расход памяти и время выполнения, поскольку ограничивает свободу оптимизации и увеличивает время жизни переменных, таким образом уменьшая возможность выполнения на основе регистров. Так как время хранения переменной в памяти увеличи- вается, то одновременно с ростом времени выполнения увеличивается загрузка RAM.
Использование в предикате. Объект используется в предикате [RAPP82], если он применяется в предикате. В выражении IF X = Y + Z... переменные X, Y и 1 использованы в предикате. В некоторых языках (например, С) объект может ис- пользоваться для вычисления и в предикате одновременно, поскольку вычисление может быть встроено в предикат. Создание моделей с одновременным использова- нием в предикате и для вычисления при тестировании поведения не дает никаких преимуществ, если только вы не ставите себе цель внести путаницу. Предикаты внутри утверждений не являются примерами использований в предикатах, так как утверждения обычно не влияют на ход выполнения или на конечные значения. Использование. Объект используется, если он задействован в предикатах и/ или в вычислениях. Входной узел. Входной узел графа потока данных, через который вводятся дан- ные. Имя входящего в этот узел объекта обычно написано в самом узле или прямо перед узлом, но, если это особо оговорено, может быть написано над исходящей из узла связью. Примеры эквивалентных обозначений входных узлов приведены на рисунке. Сэм, Джо Константы. Константы следует рассматривать как вводы и моделировать как входные узлы. Множество ошибок происходит из-за использования неправиль- ной константы, неправильного значения константы, или изменения значения кон- станты во время вычислений. Константы уязвимы для ошибок точно так же как и другие переменные и поэтому должны рассматриваться таким же образом. Узел вывода. Выходной узел диаграммы потока данных — это узел, через кото- рый выводятся данные. Имя объекта, значение которого выводится, указано ря- дом с узлом. Сэм, Джо Запоминающий узел. Пара узлов для одного и того же объекта данных. Узел на диске). Узел ВЫБОРКА определяет значение переменной в памяти. Верхнее обоз- начение на рисунке показывает, как это обычно изображается в графах потока
данных, но обозначение в нижней части рисунка выглядит яснее. Запоминающие узлы часто сбивают с толку, поскольку при последующей обработке не сразу может быть понятно, какое именно значение переменной используется: значение, сохра- ненное на диске, или значение в ОЗУ, предшествующее сохранению. Например, при использовании в сетях с файлами совместного доступа они могут отличать- ся (и таким образом быть источником ошибок). Использование двух различных имен, скажем, значение_озу и значениедиск может помочь прояснить ситуацию. Обрабатывающий узел. Узел с одной или более входящими связями и по край- ней мере, с одной исходящей связью. Входящие связи обозначают объекты дан- ных. Исходящая связь обозначает вычисленную функцию этих объектов данных. На рисунке общийдоход — это функция трех входящих связей — wages (заработная_ плата), taxabl e_i nterest (налогооблагаемые_приценты) и tax exempt (доход_осво- божденный_от_уплаты_налогов). Для ясности вы можете пометить обрабатыва- ющий узел вычисляемой функцией.
Значение связи. В графах потока данных значения объектов связаны с узлами, в которых эти значения вычисляются (то есть обрабатывающими узлами). В упро- щенных графах потока данных, используемых в данной книге, все исходящие из узла связи имеют одинаковые значения объектов данных. При обычном применении графов потока данных узел может быть использован для представления нескольких различных вычислений и, таким образом, может иметь несколько различных объ- ектов, ассоциированных с исходящими связями. Обычная практика — размещение имен объектов на исходящих из таких узлов связях. При таком использовании мы неформально называем эти имена значениями исходящих связей. Подобным же об- разом, поскольку исходящие из одного узла связи являются входящими по отноше- нию к следующему узлу, они называются значениями входящих связей. Предикат выбора данных. Предикат, значение которого (например, истин- ное значение) используется для выбора одного из нескольких объектов данных. Например, указатель на массив выбирает объект данных в массиве, на который указывает указатель. Узел выбора данных всегда имеет предикат выбора данных. Узел выбора данных. Узел, чьи входящие связи управляются предикатом выбо- ра данных. Его значение (истинности или указатель) выбирает объект данных, со- ответствующий входящей связи. На рисунке предикат выбора данных, связанный с узлом выбора данных, выбрал объект данных V1V. Узел выбора данных вычис- ляет специальную функцию выбора значения входящей связи для использования в исходящей связи. Входящие связи узла выбора данных могут быть помечены условием предиката, при котором выбирается данная входящая связь. VIV Управляющая входящая связь. Узел выбора данных может иметь входящую связь, которая используется только в предикате выбора данных. Управляющие входящие связи принято обозначать пунктирными строками. VIV -* Управляющая переменная
В предыдущем примере выбор VIV мог быть основан на значениях всех входя- щих связей: Значение_исходящей_связи: = МАКСИМУМ (значения_входящих_связей) В этом случае управляющей входящей связи нет. И наоборот, выбор мог быть основан на значении управляющей входящей связи, которое определяет, какое значение и какой входящей связи должно быть использовано: Значение_исходящей_связи: = ВЫБОР(УПРАВЛЯЮ!ЦАЯ_ПЕРЕМЕННАЯ. значения_входящих_связей) В последнем примере переменная управляющей входящей связи УПРАВЛЯЮЩАЯ- ПЕРЕМЕННАЯ выбирает одно из значений входящих связей, как, например, в случае указателя на массив. Граф потока данных. Граф, состоящий из входных узлов, узлов вывода, запо- минающих узлов, узлов выбора данных и соответствующих связей и свойств. 5.3. Отношения и модель 5.3.1. Основы Объекты (узлы): Вычисляемая функция входящих связей: 7: wages (заработная_плата) 8а: taxabl е_т nterest_i ncome (налогооблагаемь:й_доход_с_процентоз) 8b: tax_exempt_interest_1ncome (проценты_освобожденные_от_налога) 9: dividend-income (доход_от_дивидендов) 10: taxable_refunds (облагаемые_налогон_платежи_пс_долган) 11: alimony_received (полученные_алименты) 12: business_1ncome_or_loss (доход_или_потери_в_результате_предпринимате.1ьской_деятельности) 21: other_income (другие_доходы) 22: общий_доход : = заработная_плата + налогооблагаемый_доход_с_процентов + ... + другие_доходы. Обратимся к форме 1040. Узлы с 7 по 21 — источники данных. Из них узлы 8а, 9, 10, 12, 13, 14, 15, 18, 19 и 21, возможно, пришли из других форм ВНС, но будут трактоваться здесь как входные данные, чтобы не усложнять пример. Строка 22 — обрабатывающий узел. Узел 22 также зависит от узлов 15b и 16b, расчетом кото- рых мы па данный момент пренебрегаем (а вы не должны). Почти каждая строка в форме 1040 соответствует объекту данных, который вводился без предваритель- ного расчета, пришел из другой формы или был рассчитан по ходу обработки фор- мы 1040. Отношение (связи). Непосредственно используется для расчета значения. В последнем примере узлы с 7: wages (заработная_плата) по 21: other_1 ncome (дру- гие_доходы), исключая 15а: IRA (индивидуальные_пенсионные_счета (ИПС)) и 16а: pensions (пенсии), напрямую используются для вычисления значения узла 22: total income (общий доход). Эти значения также используются косвенным образом для вычисления значений других объектов — таких как узел 53: уоиг_ total_taxes (общая_сумма_ваших_налогов), но поскольку применение не являет-
ся прямым, то здесь нет прямых стрелок из этих узлов к узлу 53. Однако есть по- токи данных из некоторых из этих узлов, приходящие в узел 53. Свойства узлов (веса узлов). Пометьте узлы функцией входящих связей, кото- рую они вычисляют. Это может быть просто имя выхода функции (например, об- щий доход) или сама фактическая функция, например, формула. Свойства связей (веса связей). Добавление весов связей не является необхо- димым, поскольку эта информация заложена в весах узлов. Однако поскольку графы потока данных могут быть довольно сложными, обычно исходящие связи помечаются именами представляемых ими объектов данных. Если узел представ- ляет собой узел выбора данных, пометьте входящие связи значениями предиката выбора, соотнесенными с каждой входящей связью. 5.3.2. Аналогии с графами потока данных В графах потока управления имеются конструкции, эквивалентные конструкци- ям в графах потока данных. Простая обработка. Обычно простая обработка обозначается одиночным уз- лом обработки без принятия во внимание порядка обработки. Несмотря на то, что предыдущий пример для вычисления total income (общий_доход) выглядит упорядоченным, этого упорядочения не требуется, поскольку ВНС не настаива- ет, чтобы мы заполняли налоговые документы, сначала указывая сумму заработ- ка, затем налог па проценты, и так далее. Если мы пишем программу на обычном
языке программирования, тогда нам следует выбрать определенный порядок вы- полнения действий, но это упорядочение делается по нашему выбору и не сущес- твенно для решения задачи. В диаграммах потока данных мы не навязываем опре- деленную последовательность, не предполагаемую требованиями. Обозначение в виде списка связей удобнее графического представления. Комментарий, относящийся к связи, согласно нашей договоренности соответ- ствует первому узлу из пары. Это облегчит нам задачу, поскольку нам не придется писать список узлов и затем еще и список связей. В следующем примере коммен- тарий other_1ncome (другие_доходы) соответствует связям, исходящим из узла 21. 21: 22: other_income (другие_доходы) 11: 22: alimony_received (полученные_алименты) 15а: 15b: total_IRS_distribution (общее_распределение_ИПС) 15b: 22: taxable amount (налогооблагаемая_сумма) (справьтесь у вашего бухгалтера) 16а: 16b: taxable amount (налогооблагаемая_сумма) (справьтесь у другого вашего бухгалтера) 17: 22: rental_royalties (доходы_от_аренды) 18: 22: farm_income_or_loss (прибыль_или_убь.ток_от_сельского_хозяйства) 19: 22: unemployment_compensation (пособие_по_безработице) 20а: 20b: sociа1_secur1ty_benefit (пособие_по_социальному_обеспечению) 20b: 22: taxable_social_security_benefit (налогооблагаемые пособия_по_социальному_обеспечению) 8b: tax_exempt_interest_i ncome (проценты_освобожденные_от_налогов) 9: 22: dividend-)ncome (доход_от_дивидендов) 14: 22: другие_прибыли_и_убытки_из_формы_4797 10: 22: taxable_refunds (облагаемые_налогом_платежи_по_долгам) 8a: 22: taxablejnterest (налогооблагаемые_проценты) 12: 22: business_income_or_loss (прибыль_или_убытки_от_предпринимательской_деятельности) 7: 22: wages (заработная_плата) 13: 22: capital_gains_or_loss (капитальная_прибыль_или_убытки) 22: total_income (общий_доход): = wages (заработная_плага) + taxable_1nterest_income (налогооблагаемый_доход_с_прэиентов) + tax_exempt_interest_income (проценты_освобсжденные_от_налога) + ... + other_income (другие_доходы) He так важно, как мы переставим строки в вышеприведенном графе. Связи опре- делены, так что порядок, в котором мы расположим их на странице, не влияет на об- работку или на модель. Я включил узел 8Ь, который, как кажется, никуда не ведет; ВНС желает получить эту информацию, несмотря даже на то, что она не использует- ся в этом расчете. По-видимому, они используют ее для каких-то других расчетов. IF-THEN-ELSE. Здесь приведена спецификация для строки 36 из формы 1040 ВНС. 36 Если значение в строке 32 (Adjusted_Gross_Income (скорректированный_общий_доход)) меньше или равно $83.850. умножить $2450 на общее число льгот, заявленных в строке бе. Если сумма в строке 32 (Adjusted_Gross_Income (скорректированный_общий_доход)) больше $83.850. смотрите инструкции (ВНС 1040) для того чтобы рассчитать облагаемую сумму. Приводим модель псевдокода для этой операции. 36.1: 36: IF((СОД) строка_32 <= $ 83850) THEN строка_36: = число_ освобождений * $2450 ELSE строка_36: = расчет_согласно_инструкции.
Ниже приводится классический граф потока управления для этой операции. 36.1: 36.2: узел предиката. СОД <= $83850 36.1: 36.3: узел предиката. СОД > $83850 36.2: 36: Строка_36: = число_ освобождений * $2450 36.3: 36: Строка_36: - расчет_согласно_инструкции Переменная Строка_36 не перегружена. Почему? Вот граф потока данных для этой операции. бе: 36.1: общее_число_ освобождений kl: 36.1: значение_константы_$2450 к2: 36: значение_константы_$83850 36.1 : 36: общее_число_освобождений *kl 32: 36: adjusted_gross_income (скорректированнь:й_общий_доход) Р23: 36: расчет_согласно_инструкции 36: ... узел_выбора_данных 36.1 IF СОД <» к2 Р23 IF СОД > к2 Меня не удовлетворяет эта модель, поскольку средства управления перемеша- ны с вычислением. Действительно, замысловатая модель, могла бы запутать, так что я бы добавил несколько связей, чтобы сделать ситуацию более ясной, предло- жив следующий граф потока данных. бе: 36.1: total_number_of_exemptions (общее_число_освобождений) kl: 36.1: значение_константы_$2450 36.1: 36: total_number_of_exempt1ons (обшее_число_освобождений) * kl Р23: 36: расчет_согласно_инструкции к2: 36.2: значение_константы_$83850 32: 36.2: adjusted_gross_1ncome (скорректированной общий_дохсд) 36.2: 36: значение_селектора (управляющая входящая сзязь) 36: ... узел_выбора_данных 36.1 IF СОД <= к2 (знэчение_селектора = ИСТИНА) Р23 IF СОД > к2 (значение_селектора = ЛОЖЬ) Вы, возможно, захотите начертить все эти графы потока данных для сравнения. Модели потоков данных могут показаться более сложными по сравнению с ранее рассматриваемыми моделями, но это не так. Они только включают больше инфор- мации, чем обычно закладывается в модель потока управления. Дополнительные детали возникают вследствие того, что каждый объект данных должен откуда-то появиться. Вот почему мы добавили два узла kl и k2, отвечающие за константы $2450 и $83850 соответственно. Мы добавили связь 32 : 36 в первую модель пото- ка данных (связь 32 : 36.2 во вторую модель потока данных) потому что adjusted_ gross income (скорректированный общий доход) должен откуда-то появиться. Связь бе: 36.1 для переменной total_number_of_exemptions (общее_число_освобож- дений) была добавлена по той же причине. Если мы уберем эту дополнительную информацию (уменьшив детализацию нашей модели), мы получим даже еще бо- лее простую модель (по числу узлов и связей), чем модель потока управления. 36.1: 36: total_nurnber_of_exemptions (общее_число_осдобождений) * kl Р23: 36: расчет_согласно_инструкции 36: ... узел_яыбора_данных 36.1 IF СОД <= к2 Р23 IF СОД > к2
При качественном проектировании программных средств предполагается, что значения константам kl и к2 присвоены раньше в программе или хранятся в таб- лице. Это намного лучше, чем многократное повторение значений $2450 и $83850 в коде программы. Это правильный подход, поскольку уменьшается вероятность ошибок, при которых якобы постоянные величины в разных местах отличают- ся друг от друга. Это хорошо также для сопровождения, поскольку в том случае, когда ВНС изменит ставки налогового обложения (что неминуемо когда-нибудь случится), нужно будет изменить одно значение в одном месте1. Это, конечно, пра- вильный подход, но мы не можем быть уверены, что программист так и поступил. Но почему об этом должен заботиться тестировщик? Используя символьные кон- станты в нашей модели, мы уменьшаем вероятность ошибок там, где мы непредна- меренно используем несколько различных значений предполагаемой константы. Хороший дизайн программного обеспечения часто также хорош и для проектиро- вания теста. IF-THEN. Мне не нравятся конструкции типа IF-THEN в графах потока данных, поскольку они неоднозначны, если условие не выполняется. В графах потока уп- равления неоднозначности меньше, поскольку следующий оператор всегда подра- зумевается. Большинство конструкций IF-THEN лучше моделировать при помощи конструкций IF-THEN-ELSE, как в следующем примере- IF (предикат - ИСТИНА) then х: - функция ELSE х: = пусто Явно определяйте, что происходит с объектом данных, когда предикат не исти- нен. Например, постулат: 54: Удержан федеральный налог. Если вы используете форму 1099. отметьте [ГРАФА] можно представить при помощи следующего псевдокода и модели потока данных, соответственно. 54: If из_форм(ы)_1099 THEN графа: = отмечена ELSE графа: = не_отмечена 54.1: 54: графа = отмечена 54.2: 54: графа: - не _отмечена F1099: 54 значение ЛОЖЬ/ИСТИНА из формы 1099 54 ... узел выбора данных: 54.1 IF F1099 = ИСТИНА 54.2 IF F1099 = ЛОЖЬ Будьте осторожны с такими величинами, как ноль и пусто; это не одно и то же. Мы ввели два входных узла в последний пример: 54.1 графе: = отмечена и 54.2 гра- фа: = не_отмечена. В обоих случаях графа имеет реальное значение. Таким же обра- зом значение ноль — реальное значение, в то время как пусто не имеет какого-либо значения. Это означает — не определено. Рассмотрим оператор присваивания: IF х > 0 THEN сэм: = джо. Мы знаем, что делать с сэм, когда х > 0, но вдруг х <= 0? Есть две альтернативы: либо у перемен- ной сэм нет значения, и она здесь же и создается, либо имеется другое, заранее ’ Я начал писать эту книгу в 1992 году. Я должен был исправля п> эти числа в 1993,1994 и, наконец, еще раз в 1995 году. Однако, в отличие от вас, я не мог использовать символьную переменную для этих чисел. Было бы намного проще, если бы я мог так поступить. Если я пропустил несколько обновлений, я уверен, что вы сообщите мне об этом, — но надеюсь, что вы простите меня.
рассчитанное где-то в другом месте графа потока данных значение для сэи. Первый случай не представляет проблемы. Мы моделируем его так: IF х > О THEN сэи: = джо ELSE сэн:= пусто. Второй случай тоже не сложен. Он должен быть смоделирован так: IF х > О THEN сэи: = джо ELSE сэи: = ста;ое_значение_сэн. Нам снова не нужно сомнительное IF-THEN. Возможно, проблема возникнет, если переменная сэм определена в более чем одном месте. Какое значение нам следует использовать для случая ЛОЖЬ? Это — хороший вопрос, не имеющий простого ответа. Тут возможны варианты, пос- кольку в случае неоднозначности не бывает очевидного ответа. Конструкция IF-THEN однозначна в графе потока управления, потому что графы потока управле- ния имеют подразумеваемое упорядочение (упорядоченную последовательность). Следовательно, обычно имеется подразумеваемое (предшествующее) значение для такой ситуации. В графах потока данных, в которых нет подразумеваемого упорядочения, значение становится неоднозначным. Вот почему следует избегать использования IF-THFN в подобных моделях. Но заметьте, что неоднозначность в модели увеличивает вероятность ошибок профаммирования. В качестве примера использования IF-THEN рассмотрим, как бы мы могли смо- делировать строки с 1-й по 5-ю в форме 1040. Здесь приведен псевдокод для этих строк. 1: IF статус налогоплательщика = холост THEN отмечена графа_1; GOTO 6а 2: IF статус налогоплательщика - женат_заполнено_совместно THEN отмечена графа_2: GOTO 6а 3: IF статус налогоплательщика = женат_запогнено_раздельно THEN отмечена графа_3: GOTO 6а 4: IF статус налогоплательщика = домовладелец THEN отмечена графа_4; GOTO 6а 5: IF статус налогоплательщика = вдовец THEN обмечена графа_5; GOTO 6а Этот псевдокод не является неоднозначным в том случае, если мы знаем, что предшествующее состояние всех граф «не отмечена». Поскольку мы не можем быть уверены в этом в случае кода, содержащего ошибки, более предпочтительная модель могла бы выглядеть следующим образом: 1: IF статус = холост THEN графа_1: = отмечена: GOTO 6а ELSE графа_1: = не_отмечена 2: IF статус = жен_совм THEN графа_2: = отмечена; GOTO 6а ELSE графа_2: = не_отмечена 3: IF статус » жен_раздельно THEN графа_3- “ отмечена: GOTO 6а ELSE графа_3: = не_отмечена 4. IF статус - домовладелец THEN графа_4: = отмечена. GOTO 6а ELSE графа_4: = не_отмечена 5: IF статус = вдовец THEN графа_5: = отмечена: GOTO 6а ELSE графа_5: - не_отмечена Программисты могут возразить, что этот код нехорош, так как он неоправдан- но сложен, что само по себе делает код более уязвимым для ошибок, и, кроме того, он не структурирован. Все это правда, но ведь это не код. Это всего лишь модель, в которой мы пытаемся сделать ситуацию как можно более однозначной. Вот мо- дель потока данных для этих действий. 0.0: . 0.1 вход_статус 0.1; графа_1: графа_1: 6: выбор: IF статус = неженат выбрать отмечена ELSE выбрать не отмечена
графа_2: графа_2: 6: графа_3: графа_4: графа__3: 6: графа_5: графа_4: 6: отмечена: графа_1: графа_2: графа_3: графа_5: 6: графа_4: графа_5: 6: не отмечена: графа_1: графа_2: графа_3: графа_4: графа_5: выбор: IF статус= женсовм выбрать отмечена ELSE выбрать не отмечена выбор: IF статус = жен_разделоно выбрать отмечена ELSE выбрать не отмечена выбор: IF статус = домовладелец выбрать отмечена ELSE выбрать не отмечена выбрать отмечена ELSE выбрать не отмечена выбор: IF статус = вдовец выбрать отмечена ELSE выбрать не отмечена продолжение модели Модель может показаться сложной, но это не так, потому что определено всего пять различных выходов (по одному на кажд ую графу). В тестируемом программ- ном обеспечении, в котором реализуется этот процесс, мы должны убедиться не только в том, что правильная графа отмечена, но и в том, что все остальные графы остались неотмеченными и отмечено не больше одной графы. Заметьте, что если вход статус_налогоплателыцика не является одним из пяти правильных вариан- тов, тогда все графы останутся неотмеченными. Селектор CASE. Структура Селектора CASE в графах потока данных — обобщение структуры IF-THEN - ELSE. Модель потока данных для строки 34 такова: 34.1: 34: вход $3800 (холост, deduction (возврат): = $3800) 34.2: 34: ВХОД $5600 (домовладелец. oeduction (возврат): = $5600) 34.3: 34: вход $6350 (женат совместная декларация, deduction (возврат): = $6350) 34.4: 34: вход $6350 (вдовец. deduction (возврат): = $6.350) 34.5: 34: вход $3175 (женат, заполнено раздельно, deduction (возврат): - $3175) статус: 34: вход статус_налогоплателыцика (управляющая входящая связь для селектора 34) 34: выбор статус_налогоплательщика: холост 34.1 домовладелец 34.2 совместно 34.3 вдовец 34.4 раздельно 34.5 Строка 34 иллюстрирует работу узла CASE. Я предпочитаю использовать пере- менную статусналогоплателыцика для моделирования предиката выбора, потому что это тот способ, который используется в инструкциях ВНС. Обладая инфор- мацией, какая графа была отмечена в строках с 1-й по 5-ю, я бы создал в строках с 1-й по 5-ю модели переменную номер графы, значение которой устанавливалось бы
соответствующим той графе, которая отмечалась, и затем использовал бы значе- ние номер_графы для управления предикатом выбора в строке 34. Так же как и в случае конструкции IF-THEN, здесь возможна неоднозначность. Что произойдет, если ни одна из граф (строки 1-5) не будет отмечена? Что про- изойдет, если в строках с 1 по 5 отмечено более одной графы? 5.3.3. Короткие замечания и упрощенные методы Не забудьте, что мы имеем дело с моделями, а не с программным обеспечением. Следовательно, закладывайте в модель как можно больше деталей из тех, что вам нужны, но не все, что вам известны. Ваши модели потока данных, используемые при разработке тестов, должны иметь различные степени детализации по анало- гии с диаграммами потока данных, используемыми в проектировании. Например, имея дело с файлом, вы могли бы извлечь пользу от наличия нескольких уровней детализации (и нескольких различных моделей потока данных). Уровень файла. Рассмотрите весь файл как один объект данных, с которым об- ращаются как с единым целым. Сконцентрируйтесь на операциях, которые при- меняются к целому файлу, и на операциях между файлами, например, открыть, закрыть, копировать, сравнить, переименовать, удалить, переместить, переслать, объединить, извлечь, создать. Уровень записи. Тесты, которые вы проделали на уровне файла (если они успешно пройдены), гарантируют, что вы работаете с правильным файлом. Сконцентрируйтесь на получении правильной записи в модели для уровня запи- си. Проводимые операции аналогичны операциям на уровне файла: добавить за- пись, удалить запись, копировать запись, найти запись, извлечь, сравнить, пере- местить. Уровень поля. Рассмотрите индивидуальные поля в записи. Здесь может быть несколько уровней. Например, одно из полей может являться массивом. Рассмотрите следующие операции: вставить поле, удалить поле, изменить значе- ние поля, копировать значение, сосчитать число полей. Уровень обработки. Обычно его можно совместить с уровнем поля, но это не всегда стоит делать, если операции с полями либо обработка данных достаточно сложны. Модель обработки сама по себе может быть создана на нескольких раз- личных уровнях детализации. Группы данных. В ряде случаев (требования приложения или способ про- граммирования) вы, может быть, захотите сгруппировать те объекты данных, которые обрабатываются схожим образом, даже если они не связаны в контек- сте данного приложения. Это поможет вам создать многократно используемые модели. То есть одна и та же модель может быть использована для нескольких различных, возможно, не связанных, частей приложения. Возможность повтор- ного использования — признак хорошего программирования и хорошего дизай- на тестов. Качественное проектирование программного обеспечения упрощает задачу моделирования, поскольку разработчики создают иерархический набор потоков данных, структура которого отражена в структуре разбиения процесса обработки.
Когда вы, как об этом говорилось выше, разделяете модель на уровни, вам, воз- можно, придется «создать» новые объекты данных, которых нет в спецификациях. Определите их так точно, как если бы вы занимались программированием, задай- те их атрибуты, определения и так далее. После определения, такая псевдопере- менная становится переменной при использовании в модели потока данных более высокого уровня. При создании и использовании таких упрощенных методов вы не програм- мируете и не меняете технические требования — вы закладываете фундамент, необходимый для создания высокочувствительного теста. Если приложение сложно организовано, приготовьтесь к тому, что тесты будут, подобно ему, об- ладать сложной структурой. Если программное обеспечение выигрывает при использовании иерархической структуры, разбиения и многократно использу- емых компонентов, то выиграет и тестовый комплект. Большинство методов, использование которых оправдано при проектировании программы, окупаются при разработке тестов. Вы могли бы раскритиковать такой подход к организации разработки тестов, сказав: «Ни приложение, ни программное обеспечение не всегда бывает струк- турировано должным образом. Предполагая хорошую структуру тестируемой системы при проектировании тестов, вы можете упустить из виду возможность выявления ошибок, являющихся следствием плохой структуры, — например, ошибок, проистекающих из смешения уровней файла, поля, записи данных с их обработкой». Подобный критицизм заслуживает внимания, но из того, что структура про- граммы размыта, не следует того, что плохо структурированное тестирование бу- дет более эффективным. Не следует доверять поимку вора вору. Необходимо ра- ботать систематично. Как можно повысить эффективность использования скудного времени, отпу- щенного на проектирование тестов? Существует гораздо больше способов спроек- тировать программное обеспечение плохо, чем способов сделать это хорошо. Если вы решили придерживаться неструктурированного проектирования тестов в по- пытке найти некоторые ошибки, вы можете также ошибиться в предположениях о коде, как и при хорошо структурированном проектировании. Вы обманываете са- мих себя. Единственный способ сделать обоснованные допущения о коде, на кото- рых можно основать проектирование тестов, — это посмотреть на код и построить дизайн ваших тестов в соответствии с его структурой. Но это уже нельзя назвать тестированием черного ящика. Приняв структурированную модель, вы увеличиваете вероятность того, что ваши позитивные тесты будут обеспечивать покрытие требований. Такой на- бор тестов более объективен и при создании негативных тестов. Например, раз- деляя тесты на уровне файла и полей записи, вы можете яснее увидеть, какая имеется возможность для грязных тестов, в которых эти уровни перемешаны. Проектирование грязных тестов будет проще и потребует меньшего количества предположений об ошибках, так что работу будет проще оценить.
5.3.4. Упорядочение, совмещение потока управления и потока данных, циклы 5.3.4.1. Упорядочение Ссылки на материал, описанный в этом разделе, можно встретить в [RUGG79]. Данная книга рекомендуется для дополнительного ознакомления с рассматрива- емыми концепциями. Граф потока данных содержит мало указаний о порядке обработки, продикто- ванном используемыми языками программирования и аппаратным обеспечением. Но некоторое упорядочение все же остается, и информация о некотором упорядо- чении будет уместна. Вот четыре общих вида упорядочения, которые могут встре- титься в графе потока данных: удобное, но не необходимое, необходимое, синхро- низация, итерирование. Не необходимое, но удобное. У нас есть последовательность операций, которые рассчитывают значения вместе с промежуточными значениями. Вам необходимо знать ad justed_gross_1 ncome (скорректированный_общий_доход) (строка 31), для того чтобы рассчитать величину вашего налога, ad,lustea gross income (скоррек- тированный_общий_доход) зависит от переменной total income (общий_доход) (строка 22), которая, в свою очередь, зависит от других полей. В конечном счете эти поля зависят от входных данных. Может показаться, что подобное упорядо- чение необходимо, но это не так. Каждая строка в налоговой декларации может быть (теоретически) выражена прямо в виде комбинации входных данных. Так поступить допустимо, но глупо, потому что каждая строка в налоговой форме в этом случае была бы суммой множества вводимых полей. Такое упорядочение удобно, но не необходимо. Если вы уберете все подобное упорядочение из типич- ной диаграммы потока данных, вы получите только входные узлы и (очень слож- ные) выходные узлы. Когда вы видите граф потока данных, содержащий между узлами входа и вы- хода еще другие узлы, проверьте эти промежуточные узлы, чтобы определить, яв- ляются ли они необходимыми или просто удобны. Можно ли упростить или сис- тематизировать ваш граф, удалив некоторые из этих упорядочений и выразив выходы более явно через входные данные? Это диаметрально противоположно тому, что вы делали, когда изучали псевдопеременные и иерархические разбие- ния в разделе 5.3.3. Необходимое. Иногда упорядочение необходимо. Вы не можете прочитать файл, до того как он создан (несмотря на то, что это хороший тест) или закрыть неоткрытый файл. Вы должны понять, как работает приложение, чтобы узнать, является ли упорядочение в графе потока данных необходимым или нет. Не уда- ляйте необходимое упорядочение, потому что если вы это сделаете, вы пропустите полезные тесты и создадите бесполезные. Синхронизация. Если имеются параллельные процессы (например, в систе- мах с общими данными или сетевых приложениях), тогда существует необхо- димое упорядочение и проблема синхронизации. Например, с: = а + Ь, где а и b берутся из разных мест. Проблема синхронизации приводит к пяти до- полнительным тестовым вариантам, зависящим от последовательности собы-
тий (почему?), и ее мы обсудим в главе 6. Если в вашем случае таких проблем достаточно много, может оказаться, что модель потока данных не подходит для данного случая, и лучше рассмотреть модель потока управления или модель по- тока транзакций. Итерирование. Если у вас есть узлы выбора, вы можете вернуть результат вы- числения назад, в более раннюю точку на графе потока данных и создать цикл. Процесс повторяется до тех пор, пока (как мы надеемся) не выполнится условие прекращения. Циклы и способы их обработки в контексте модели потока данных обсуждаются в разделе 5.3.4.3. 5.3.4.2. Совмещение потока управления и потока данных Модели потока управления и модели потока данных плохо сочетаются [KAVI87], Каждая модель — это обособленная часть общей картины, сосредоточенная на од- них аспектах проблемы и игнорирующая другие. Модель — это способ структури- ровать наше мышление, необходимый для получения полезных тестов. Если мо- дель чересчур сложна, это только запутает нас. По как мы должны обрабатывать необходимое упорядочение в рамках модели потока данных? Вот некоторые со- ображения. Более одной модели. Сделайте отдельно модель потока данных и модель потока управления. Каждая приведет к различным тестам, и? как мы надеемся, при таком подходе не будет значительного перекрытия созданных тестов. Возможно, вы пред- почтете в качестве альтернативы модель с конечным числом состояний (глава 9). Поместите модель потока управления внутрь модели потока данных. У вас есть повторяющаяся процедура в модели, большей частью определяемой потока- ми данных. Например, вы должны найти файл, чтобы получить данные, которые затем используются в вычислении. Рассматривайте поиск файла как единичную операцию внутри модели потока данных. Для поиска файла используйте модель потока управления. Поместите модель потока данных внутрь модели потока управления. Скажем, вы проделываете повторяющуюся обработку для каждой записи файла. Обработка моделируется при помощи графа потока данных. Расположите часть, представля- емую потоками данных, внутри модели файла (либо модели потока управления или модели потока транзакций). Рассматривайте файловую часть как модель по- тока управления, а обработку как модель потока данных. Когда вы проектируете тестовый вариант, никто не знает, как вы это делаете. Тестовый вариант состоит из исходных условий, вводимых данных, ожидаемых результатов. И история умалчивает (или должна умалчивать) о том, получили ли вы эти результаты, используя модель потока управления, модель потока данных или каким-то другим способом. 5.3.4.3. Циклы Как бы вы ни моделировали проблему и какие бы ни были в ней циклы (необходи- мые или нет), вам следует использовать методы тестирования циклов из главы 4. К счастью, в потоковых моделях нам нечасто приходится иметь дело с циклами. Мы должны различать необходимые и несущественные циклы.
Причиной возникновения несущественных циклов является природа языков программирования. Если вы хотите добавить два массива, в большинстве ком- пьютеров или языков вы, вероятно, проделаете это с помощью цикла. Цикл не необходим, потому что на параллельном компьютере вы могли бы проделать эту операцию параллельно. Большинство циклов, встречаемых нами в программном обеспечении, несущественны. Большинство детерминированных циклов не явля- ются необходимыми. Необходимые циклы реализуют итерационные или потенциально бесконечные процедуры. Решение уравнения с помощью итерационного процесса, такого как итерация Ньютона—Рафсона, — хороший пример. Поиск и сортировка файлов с неограниченной длиной — другие два примера. Большинство недетерминирован- ных циклов являются необходимыми1. Если у вас есть какие-нибудь необходимые (или удобные) не очень сложные циклы (то есть не вложенные, без переходов в них или из них, без большого коли- чества управляющей логики в них), тогда простой и эффективный путь рассмот- реть проблему цикла в рамках модели потока данных — это развернуть цикл. Рассмотрим модель, приведенную на рисунке, пренебрегая пока что различия- ми между графами потока управления и графами потока данных. Итерационный процесс здесь зависит от входных переменных А, В и С. В ходе этого процесса про- исходит вычисление функции X и счетчика цикла I. Рассчитав первый результат (Х(), программа переходит к узлу ЦИКЛ, где принимается решение о том, следует ли выйти или же продолжить. Управляющий предикат может быть функцией как X, так и I, либо обоих параметров. Нам необходимо знать исходное значение для X, потому что выполняемое в узле X вычисление зависит от предыдущего значения X. Я назвал исходное 1 * * * 5 1 Мы все знаем, что подготовка наших налоговых деклараций — повторяющаяся процедура, кото- рая производит впечатление бесконечной (до 15 апреля). Зная особенности бюрократического мыш- ления, я очень надеялся найти много необходимых циклов в налоговых законах. Я просмотрел все формы и инструкции (это порядка 950 страниц терминологии ВНС) в моем налоговом пакете. Я об- наружил множество способов уйти от уплаты налогов, но не нашел ни одного необходимого цикла. Я уверен, что они там есть, но я не эксперт по налогам, так что я не смог найти пи одного. Любой читатель, который укажет мне на необходимые циклы, чтобы использовать их в качестве примеров в последую- щем издании книги, получит бесплатный экземпляр этого издания. 5 Заж 770
значение Хо. Нам также нужно исходное значение для счетчика итераций 10. Мы не знаем, действительно ли код содержит эти исходные значения в виде явно вы- раженных констант, но, следуя логике, полагаем, что они существуют. Опыт гово- рит нам, что ошибки исходных значений случаются сравнительно часто, так что это имеет смысл проверить. Первая модель мне не нравится. Она не настолько близка к модели потока дан- ных, насколько мне бы хотелось. Узел ЦИКЛ имеет скрытую сложность, и наиболее важный вопрос — каким образом выбраны исходные значения? Модель на следу- ющем рисунке более ясна. Я добавил два узла выбора данных (помеченных «?»), чтобы выбрать между исходными значениями X и I. Я также ввел управляющую связь из селектора I к селектору X, чтобы показать, как программа могла бы вы- бирать между исходным значением Хо и последующим значением Хг Например, там мог бы находиться предикат в форме IF I = О THEN ВЫБРАТЬ X, ELSE ВЫБРАТЬ Хо. В случае реальной проблемы вам следовало бы иметь больше информации о спе- цифике условий прекращения цикла и разместить больше этой информации внут- ри чисто потоковых (по данным) узлов. Например, условие прекращения цикла может быть основано на разнице между предыдущим и настоящим значениями X и сравнении ее с некоторой маленькой константой е. Я развернул цикл дважды в следующей модели. Узел Х( производит исходное вычисление, основанное на исходных значениях Х(1 и 1„. Узел Х2 вычисляет функ- цию, основанную на константах А, В и С, и использует новые значения X и I. Из-за инициализации функции ее значение для Х2, вероятно, не будет тем же самым, что и для Хг Для узла Х,(, который, вероятно, имеет то же значение функции, что и Х2, цикл снова развернут. Мы можем продолжить разворачивать цикл и получим модели для большо- го числа повторений (и, следовательно, с многочисленными узлами и связями). Но это не очень хорошая идея. Сколько раз нам следует разворачивать цикл? Дважды!1 Это дает вам три модели: первая остановится в узле Хг вторая остано- 1 Мы должны развернуть один раз — чтобы удовлетворять требованиям методик структурного тестирования, поскольку мы хотим использовать простые пути. Второй разворот оправдан опытом и теоремой Хуанга. Смотри [BEIZ90].
вится в узле Х2 и третья — в узле Х.(. Это три отдельных модели, позволяющие рассмотреть три случая — выход без прохождения цикла, выход после однократ- ного прохождения цикла и выход после двукратного прохождения цикла. Если вы должны протестировать максимальное число итераций, используйте модель пото- ка управления. При тестировании циклов в модели потока данных мы з основном занимаем- ся поиском ошибок инициализации или использования неправильных значений для предварительной итерации. Например, в узле Х3 вместо использования вели- чины Х2 программист использует величину Х1 или Хо. И теория, и практика пока- зывают, что однократное и двукратное прохождение цикла позволяют найти боль- шинство подобных ошибок. 5.4. Методы 5.4.1. Основы Ссылки на материал, описанный в этом разделе, можно встретить в [SNEE86, ZWEB92], Данные книги рекомендуются для дополнительного ознакомления с рассматриваемыми концепциями. Проектирование и выполнение тестов остаются такими же, как и для моделей потока управления, с незначительными различиями, которые вытекают из того, что мы имеем дело с графами потока данных, а не с графами потока управления. В дальнейшем я буду предполагать, что у нас нет циклов. 1. Проверьте спецификацию. 2. Идентифицируйте входные переменные, особенно константы. Дайте каж- дой входной переменной имя и создайте для нее входной узел.
3. Перепишите спецификацию таким образом, чтобы каждой вычисляемой функции соответствовало одно предложение. 4. Перечислите функции, начиная с тех, которые зависят только от входных переменных. 5. Перечислите функции, зависящие только от входных переменных и резуль- татов функций, перечисленных в пункте 4. 6. Продолжайте подобным образом перечислять функции, пока не охватите их все. У вас должен получиться список, в котором наверху будут находиться функции, зависящие только от входных переменных, а далее, по мере про- движения вниз, будут находиться функции, зависящие от всё большего ко- личества промежуточных вычислений. Заметьте, что, как правило, строгое упорядочение невозможно, но это и не нужно. 7. Проверьте промежуточные функции (в том числе функции, зависящие от входных переменных и от выходных данных других функций) и посмот- рите, является ли упорядочение необходимым или просто удобным. Если оно необходимо, пометьте соответствующий узел, а также узлы, которые дикту ют эту необходимость. Если упорядочение не обязательно, посмотрите, мож- но ли упростить модель, удаляя промежуточные узлы и выражая функцию непосредственно через входные переменные? Если вы можете удалить узлы и связи без чрезмерного усложнения вычисляемой функции, сделайте это. 8. И наоборот, возможно, вы сможете упростить модель, добавляя промежу- точный узел для сложного вычисления. Однако если вы проделаете это, вы должны проверить, является ли ваше промежуточное вычисление верным. Возможно, для этого придется модифицировать исходный код и добавить оператор утверждения. 9. Теперь у вас есть набор узлов (из них каждый имеет имя) которые выража- ют обработку простейшим для вас способом1. 10. Имеется некое вычисление или функция, связанная с каждым узлом. Переменные в имени данной функции соответствуют узлам, с которыми связан данный узел, то есть, связям. Теперь у вас есть модель. 11. Проверьте вашу модель. Проверьте вашу работу. Действуйте точно так же, как в случае моделей потока управления. Здесь будут некоторые отличия в деталях, которые мы рассмотрим в дальнейших разделах. Но для начала нам потребуются определения. Подграф. Часть графа, которая соответствует правилам построения графов то есть имеющая узлы входа и выхода, не имеет оборванных связей, не имеет изоли- рованных узлов, и так далее. 1 То, что обязательно для вас, совсем не обязательно для меня, и наоборот. Никогда не забывайте, что модели — это мысленные инструменты и что в них нет чего-либо принципиально правильного или неправильного. Они могут быть только полезными или бесполезными. Вы можете предпочесть сохра- нить несущественное промежуточное вычисление в модели, поскольку знаете, что это будет выгодно в другом контексте или просто потому, что люди часто склонны думать подобным образом.
Порожденный подграф. Подграф графа, выбранный в соответствии с определен- ным критерием так, что для данного критерия подграф обладает всеми свойства- ми полного графа для выбранных узлов и связей [WEIS81, WEIS84], Критериев много, и таким образом, существует много различных порожденных подграфов. Если, например, граф представляет собой граф потока управления и интересу- ющий нас критерий — это поведение вдоль пути, то подграф содержит модель все- го кода вдоль выбранного пути. Здесь мы в основном заинтересованы в порожден- ных подграфах потоков данных. Порожденный подграф потока данных. Порожденные подграфы потоков дан- ных выбираются по отношению к объектам данных; в пашем случае — обычно по отношению к выходному узлу. В общем случае, однако, порожденный подграф по- тока данных по отношению к данному объекту (узлу) — это подграф графа пото- ка данных, содержащий все потоки данных, которые прямо или косвенно могут прийти в заданный узел, и все потоки данных, которые могут быть доступны из этого узла. Если порожденный подграф (как обычно) выбирается по отношению к выходному узлу, то в этом случае он содержит все узлы, которые могут повлиять на значение соответствующей выходной величины. Проще говоря, вы просто отслеживаете все входящие в интересующий вас узел связи и помечаете их, затем помечаете все связи, входящие в те узлы, из которых данные связи исходят, и так далее, и то же самое проделываете для исходящих связей, вплоть до выходных узлов'. 12. Выберите «пути» тестирования. Это в действительности не пути, а порож- денные подграфы. 13. Активизируйте порожденные подграфы. 14. Предскажите и запишите ожидаемые итоги. 15. Определите критерий соответствия для каждого из тестов. 16. Выполните тесты. 17. Подтвердите итоги (например, значения узла выхода). 18. Подтвердите значения в промежуточных узлах. 5.4.2. Иерархия покрытия* 2 Ссылки на материал, описанный в этом оазделе, можно встретить в [CLAR89, RAPP82, RAPP85, SCHL70, WEIS91, WEYU90, WEYU94A], Данные книги реко- мендуются для дополнительного ознакомления с рассматриваемыми концепциями. ' Задается транзитивным замыканием отношения «напрямую соединен с». 2 Для ортодоксов модели потоков данных, обсуждаемые в данной книге, — это интерпретации формально определенных критериев структурного тестирования для потоков данных, но вновь истол- кованные в терминах поведенческого тестирования. Оправдание для такой интерпретации основано не на каком-либо глубоком теоретическом анализе, а на общем смысле и опыте. Как бы то ни было, хотя большая часть поведенческого тестирования является эвристическим и в его основе лежат факты, полученные опытным путем, подобное тестирование должно в максимальной степени соответствовать и быть основанным на более фундаментальных, основополагающих структурных методах.
Методы тестирования потоков данных более эффективны, чем методы тести- рования потоков управления. Более эффективны в том смысле, что они могут об- наружить больше ошибок. Они также более эффективны с точки зрения теории, поскольку модель помогает нам создать все тесты, которые мы могли бы создать с помощью тестирования потоков управления и еще некоторые дополнительные тесты. Однако за это приходится расплачиваться. Чтобы достичь более эффек- тивного тестирования, вам приходится проделать больше работы. Больше работы, во-первых, при проектировании тестов, а, во-вторых, при проверке результатов тестирования. Приведенные ниже методы тестирования, используемые в графах потоков данных, расположены по степени возрастания их эффективности. Покрытие ввода/вывода. Рассмотрим каждый выходной узел отдельно (по- мните, что граф потока данных имеет по одному выходному узлу на каждый вы- вод). Для каждого выходного узла используйте набор входных значений, которые приводят к определенному значению вывода. В этой технике есть очевидное сла- бое место. Мы обеспечим покрытие входных и выходных узлов и, возможно, неко- торых промежуточных узлов, но если среди них имеется отдельный предикат вы- бора, мы можем быть уверены в том, что используется только одно значение этого предиката. Другие не будут протестированы. Эта проверка слишком слаба, чтобы быть нам полезной. Она гарантирует нам только то, что программное обеспечение работает для одного набора входных данных и, очевидно, не делает ничего плохо- го — например, сбоя. Забудьте об этом методе. Ввод/вывод + все предикаты. Давайте попробуем нечто посильнее. Усилим пок- рытие ввода/вывода, следя за тем, чтобы все предикаты (включая предикаты пото- ка управления для циклов и другого необходимого упорядочения) были проверены для обоих значений истинности и аналогично для предикатов в операторах CASE. Это уже лучше, но все же недостаточно хорошо. Что, если есть промежуточ- ные вычисления, результаты которых не используются? Мы не сможем их обна- ружить, не так ли? В качестве другой возможности рассмотрим следующий вари- ант. Мы рассчитываем величину X, но не используем ее, поскольку где-то позже на этом пути мы пересчитываем величину X без использования первого значения. В этом случае селекторы отсутствуют. Вычисление чего-либо без последующего использования полученного результата — это, скорее всего, ошибка, которая чаще всего является лишь неоправданной тратой ресурсов, но иногда может быть опас- на. Тут стоит взглянуть на дело со стороны. Наша модель основана на том, что, как мы надеемся, является корректной реализацией исходных требований. Но мы же тестируем реализацию, содержащую ошибки. Следовательно, промежуточное вы- числение, выход которого не используется, по всей видимости, является ошибкой, и мы должны стараться ее обнаружить. Процитируем Раппса и Веюкера [RAPP82]: «Нельзя быть уверенным в про- грамме, если нельзя увидеть эффект от использования величины, полученной... в ходе каждого вычисления». Если мы просто проверили все узлы с предикатами (как потока управления, так и выбора данных), мы добились большего, чем тестирование ветвей потока управления (из-за проблемы составных предикатов), но мы не получили бы всех тех преимуществ, которые дает тестирование потоков данных.
Частичное покрытие узлов. Предыдущие методы обеспечивали покрытие некоторых узлов и некоторых связей, но при этом не гарантировали, что будет обеспечено покрытие всех узлов и/или всех связей. Таким образом, зная, что цель нашей стратегии, по крайней мере, обеспечить покрытие вычислительных узлов нашей модели, давайте удостоверимся, что так оно и есть на самом деле. Это называется стратегией всех определений, поскольку каждый вычислитель- ный узел в нашей модели потока данных соответствует определению некоторой переменной. Заметьте, что это не обеспечивает покрытия связей. Таким обра- зом, эту стратегию нельзя прямо сравнивать со стратегией ввод/вывод + преди- кат, описанной ранее. Что эта стратегия значит? Мы создаем и выполняем достаточно тестов, чтобы быть уверенными в проверке каждого вычислительного узла нашей модели. Это означает, что каждая функция была выполнена хотя бы один раз и дала (по край- ней мере, мы надеемся на это) правильное значение для этого случая. Заметьте, что мы отвечаем за проверку промежуточных результатов, поскольку тестирова- ние каждого вычислительного узла подразумевает проверку вычисления, сделан- ного в этом узле. Стратегия все определения (ВО) представляет определенный интерес, по- скольку в ранней литературе, посвященной эвристическому тестированию пото- ков данных, обычно предлагался этот метод [BEND70, BEND85, HERM76]. Здесь наши методы основаны на формальной, проверенной теории [FRAN88, RAPP82], ВО также упускает слишком многое. Например, этот метод может пропустить все узлы выбора и все циклы в модели. Этого достаточно, чтобы отказаться от такого метода. Нам нужно что-то более сильное. Все узлы. Следующая очевидная ступень — убедиться, что мы покрываем все узлы, а не только вычислительные. Это, несомненно, более сильное утверждение, потому что мы хотим быть уверены, что в дополнение к вычислительным узлам мы обеспечиваем покрытие всех узлов выбора данных и узлов потока управления. Но это недостаточно сильно, поскольку, например, не дает гарантии, что мы про- верили все варианты для предикатов выбора и потока управления. Требуется не- что еще более сильное. Покрытие связей (все использования). Следующая логическая ступень — охват всех связей в графе потока данных. Она соответствует стратегии всех использова- ний. Всякий раз, когда вычисление выполнено, мы будем проверять каждое ис- пользование результата этого вычисления в последующей обработке. Это, ко- нечно, подразумевает проверку всех промежуточных вычислений, а не только конечных выводов. Но это не означает тестирования каждого возможного пути в программе. Это даже не тестирование всех возможных путей между точкой опре- деления и местом его последующего использования. Все использования + циклы. Существует много не охваченных здесь других стратегий тестирования потоков данных. Для того чтобы получить общее пред- ставление о них, смотрите [WEYU94A] в [MARC94], Нам следует попытаться не допускать циклов в наших моделях потока данных, но это не всегда возможно. Если у вас есть подобные циклы, тогда разверните модель и добавьте к вашим тес- товым вариантам покрытие связей развернутой модели'.
5.4.3. Построение модели Настало время прекратить теоретизирование и начать построение модели. Давайте разработаем упрощенный вариант для строк с 54 по 60 формы 1040. Вот исход- ный материал, скопированный из документа ВНС с минимальными изменениями, введенными для ясности. 54: Federal Tax Withheld (Удержанный федеральный налог) 55: 1994 Estimated Tax Payment (Выплата налога со всех видов дохода в 1994) and Amount Applied from 1993 Return (Сумма, заявленная в декларации 1993) 56: Earned Income Credit (Налоговые льготы, предоставляемые получателям заработной платы) 57: Amount Paid with Form 4868 (Extension Request) (Сумма, уплаченная в соответствии с формой 4686 (Просьба о продлении)) 58а: Excess Social Security and RRTA Tax Withheld (Налог на превышение социального обеспечения) 59: Другие выплаты в соответствии с формой 2439 или фирмой 4135 60: Общий платеж: сумма строк с 54 по 59. Первое приближение нашей модели почти полностью совпадает со строками налоговой декларации и лишь имеет слегка более формальный вид. В глубине души я надеюсь использовать инструмент, который поможет мне проверить пол- ноту и непротиворечивость этой спецификации, так что заблаговременная форма- лизация — хорошая идея. 54: 60: Federal_Tax_Withheld (Удержанный_федерал»ный_налог) 55: 60: 1994_Estimated_Tax_Payment (Выплата_налога_со_всех_видов_дохода_в_1994) and Amount_Appl1ed_from_1993_Return (Сумма_заявленная_в_декларации_1993 ) 56: 60: Earned_Income_Credit (Налоговые_льготы_предоставляемые_получателям_заработчой_платы) 57: 60: Amount_Paid_with_Form_4868 (Extension_Keauest) (Сумма_уплаченная_в_соответствии_с_формсй_4868 (Просьба о продлении)) 58а: 60: Excess_Social_Security and RRTA_Tax_Withheld (Налог_на_превышение_социального_обеспечения) 59: 60: другие_выплаты (в соответствии с формой 2439 или формой 4136) 60: Общий Платеж: сумма строк с 54 по 59. На самом деле это неправильно, не так ли? Строка 55 по сути является суммой двух слагаемых, строка 58а — сумма двух слагаемых, и строка 59 тоже является суммой двух слагаемых (форма 2349 и форма 4136: Налог со всех видов дохода в 1994 и Сумма, взятая из декларации 1993, соответственно). Мы создадим более детальную модель. 54: 60: Federal_Tdx_Withheld (Удержанный_федеральный_налог) 55а: 55: 1994_Estimated_Tax_Payment (Выплата_налога_со_всех_видов_дохода_в_1994) 55b: 55: Amount_Applidd_from_1993_Return 1 Нам нужна одна из стратегий «всех использований», но не настолько мощная, как проверка всех путей, которая в контексте поведенческого тестирования просто неосуществима
(Сумма_заявленная_в_декларации_1993 ) 55: 60: 55а + 55b 56: 60: Earned_Income_Credit (Налоговые_льготы_предоставляемые_получателям_заработлой_платы) 57: 60: Amount_Paid_w1th_Form_4868 (Extens1on_Request) (Сумма^уплаченная_в_соответствии_с_формой_4868 (Просьба о продлении)) 58al: 58а: Excess_Soc1al_Secunty_Tax_W1thheld (Налог_на_превышение_социального_обеспечечия) 58а2: 58а: Excess_RTTA_Tax_Withheld (Налог_на_превышение_Р8ТА) 58а: 60: 58а1 + 58а2 59а: 59: Другие_выплаты_в_соответствии с Формой 2439 59b: 59: Другие_выплаты_в_воответствии с Формой 4136 59: 60: 59а + 59b 60: Total Payments (Общие выплаты):= 54 + 55 + 56 + 57+ 58а + 59 Последняя строка мне не нравится из-за ее двусмысленного представления. Речь шла об узлах 54,55 и так далее, или об их значениях? Будет лучше внести яс- ность и заменить эту строку такой: 60: Total Payments: С54 + С55 + С56 + С57 + С58а + С59 В этой модели я сделал некоторые предположения, которые могут быть, а мо- гут и не быть верными. Во всех случаях, когда я детализировал узел (55,58а и 59), я предполагал, что входные данные могут прийти из ниоткуда, из одного или всех доступных источников. Эти узлы не являются узлами выбора данных. Узлы вы- бора должны иметь дело с взаимоисключающими случаями. Например, строка 38 — это узел выбора, так как в нем делается выбор между взаимоисключающими случаями. Откуда вам об этом узнать? Вы должны понять приложение и его зада- чи. Давайте смоделируем только одну строку 38 и то, что она за собой влечет. 38 Налог Отметить, если из а [ ] Tax Table (Таблицы налогов), b [ ] Tax Rate Schedule (Схемы налоговых ставок), с [ ] Capital Gain Tax Worksheet (Таблицы налога на капитальную прибыль) или d [ ] Формы 8615. е. Сумма из форм(ы) 8814 Я не являюсь специалистом по налогам, так что я должен был читать инструк- ции ВНС и руководство по налогам, чтобы понять, что делать с пунктом е. Пункт е должен быть добавлен в налог, несмотря на то, что в форме это не указано. Пункты а, Ь, с и d — взаимоисключающие и формируют соответствующий узел выбора. Ниже приводится модель для данного случая. 38а: 38х: часть_налога (Используйте Tax Table (Таблицу налогов)) 38b: 38х: часть_налога (Используйте Tax Rate Schedule (Схему налоговых ставок)) 38с: 38х: часть_налога (Используйте Capital Gain Tax Worksheet (Таблицу налога на капитальную прибыль)) 38d: 38х: часть_налога (Из Формы 8615) 38х: ВЫБОР (исходя из правил 8НС) 38а 38b 38с 38d 38е: 38: Сумма_из_Форм(ы) 8814 38: С38х + С38е
5.4.4. Выбор основного порожденного подграфа Нам надо рассмотреть несколько различных ситуаций для выбора порожденного подграфа — эквивалента путей потока управления в диаграммах потока данных. То, что мы делаем, зависит от того, что представляет собой граф потока данных. 1. Нет узлов выбора, нет узлов потока управления (и нет циклов). 2. Только потоки данных и узлы выбора. 3. Только узлы предикатов потока управления, без узлоз выбора. 4. Узлы предикатов потока управления и узлы выбора. 5. Циклы. Случай 1: Чистые потоки данных Следующую процедуру необходимо проделать для каждого выходного узла. Выберите выходной узел. Проследуйте в обратном направлении от выходного узла ко всем соединенным с ним узлам. Проследуйте от этих узлов в обратном на- правлении к тем узлам, которые, в свою очередь, соединяются с ними, и так далее, пока не достигнете входных узлов (для данной модели). Теперь у вас есть порож- денный граф потока данных. Символически ситуация проиллюстрирована следу- ющим образом: UI, U2 и U3 — выходные переменные. А, В и С — наборы входных переменных. Средняя область содержит вычислительные узлы. U1 зависит только от входных переменных из набора A. U2 зависит как от переменных из А, так и от перемен- ных из В, a U3 зависит только от переменных из С. У нас есть три набора тестов, соответствующих UI, U2 и U3. Если здесь нет узлов выбора и нет узлов потока данных, вам потребуется только один тестовый вариант на одну выходную пере- менную. Заметьте, что каждый порожденный подграф будет содержать (возмож- но) различные вычислительные узлы в области ВЫЧИСЛЕНИЕ. Например, нам следует ожидать, что вычислительные узлы, относящиеся к U3, не будут перекры-
ваться с узлами, соотносящимися с U1 и U2. Некоторая часть вычислительных узлов (но не все) будет, вероятно, использоваться как в U1, так и в U2. Случай 2: Только потоки данных и узлы выбора Начните, как и раньше, с порожденного подграфа для каждой выходной перемен- ной. Однако когда вы достигнете узла выбора, вы должны включить в порожден- ный подграф каждый потенциально выбираемый вариант. Результатом будет не- что вроде объединенного порожденного подграфа, поскольку в данном случае имеется множество альтернативных путей. Каждый объединенный порожденный подграф приведет к получению целого набора тестовых вариантов. Рассмотрите отдельно каждый объединенный порожденный подграф. Допустим, что в порожденном подграфе есть только один узел выбора. Выберите величину для каждого значения предиката выбора и затем исключите из порож- денного подграфа все потоки данных, которые не принимают участия в определе- нии этой величины. Если, например, в строке 38 мы выберем 38а (Использовать Тах Table (Таблицу налогов)), то нам следует исключить из порожденного подграфа по- токи данных, приводящие к строке Использовать Tax Rate Scnedule (Схему налого- вых ставок). Использовать Capital Gain Tax Worksheet (Таблицу налога на капитальную прибыль) и Использовать форму 8615. Порожденный подграф, основанный на U, включает в себя три вычислитель- ные области, наборы данных А, В, С, D и узел выбора. Если мы выберем величи- ну X, которая зависит только от наборов данных А и В, мы исключаем из порож- денного подграфа наборы данных С и D и вычислительную область Y. Напротив, если мы выберем величину Y, то в этом случае исключаем набор А и вычислитель- ную область X, поскольку входные наборы данных В, С, и D используются для вы- числения Y и U по мере прохождения порожденного подграфа. Предположим, что в порожденном подграфе имеется два или более предикатов выбора. У нас опять есть два случая: при обратном движении по потокам (от вы- хода к входу) они могут соответствовать или ветвлению, или слиянию потоков
данных. Сначала мы рассмотрим более простой случай, при котором в двух пре- дикатах выбора происходит ветвление потоков. Это изображено на следующем рисунке. U Мы начинаем с разделения на порожденные подграфы всех выходных пере- менных. Так же, как и прежде, выбираем одну из переменных и определяем по- рожденный подграф для этой переменной. Как и раньше, первый встреченный нами предикат выбора делит граф на несколько порожденных подграфов, каж- дый из которых приводит к набору тестовых вариантов. На рисунке есть порож- денный подграф для W, приводящий только к одному тестовому варианту, и еще один порожденный подграф для V. Следуя от V в направлении входных узлов, мы встречаем второй узел выбора, который снова порождает два варианта, приводя к порожденному подграфу для X, включающему наборы входных переменных А, В и другому набору для Y, включающему наборы входных переменных В, С и D. Помните, что узел выбора может иметь много ветвей, и вы должны разрабатывать отдельный набор тестов для каждой ветви. И теперь рассмотрим последний случай, в котором потоки данных сливаются и следуют назад вместе. Если мы возьмем порожденный подграф V для нижнего узла выбора и проследуем по нему вверх, мы натолкнемся на другой узел выбора, приводящий к двум новым порожденным подграфам и двум тестовым вариантам, соответствующим выбору X или Y. Порожденный подграф W, однако, идет назад к тому же узлу выбора (X, Y) где снова имеется возможность выбора из двух вари- антов. Приведет ли это к еще двум тестовым вариантам или только к одному? Это зависит от того, насколько тщательно вы хотите тестировать. Если вы вы- берете только один вариант для W, что дает только один порожденный подграф (либо X, либо Y), тогда у вас будет один дополнительный тест. При более тщатель-
ном (и требующем больших затрат) тестировании вам следует взять оба порож- денных подграфа. В нашем примере это добавляет только один тест, но если у нас есть много узлов выбора, расположенных один за другим в каждом порожден- ном подграфе, разница в подходах может стать разительной. Эти два метода соот- ветствуют применению того, что формально известно как критерий всех исполь- зований {ВИ) (берется какой-либо один порожденный подграф, который влияет на значение W) и критерий Всех путей-определение-использование (ВПОИ) (бе- рется каждый порожденный подграф, влияющий на значение W). ВПОИ — более полный метод, чем ВИ, но требует больших трудозатрат. Исходя из эмпирическо- го доказательства, приведенного в [WEYU90], вы сможете получить больше пре- имуществ, выбрав ВИ. Таким образом, убедитесь, что вы включили по крайней мере один порожденный подграф для каждого выхода, а не все возможные порож- денные подграфы, которые появляются вследствие всех возможных комбинаций выбора в селекторах (и, как мы увидим, всех комбинаций значений для предика- тов потока управления и условий циклов). Случай 3: Предикаты потока управления без узлов выбора Этот случай обрабатывается тем же способом, что и узлы выбора. Начиная с конца графа, от выходных переменных, создайте порожденный подграф. Правда, здесь есть отличие от предыдущего варианта. В узле выбора данных в порожденный под- граф войдет только одна входящая связь. То есть каждая входящая связь создает новый порожденный подграф. В узле потока управления (например, IF-THEN-ELSE или CASE) каждая исходящая связь создает новый порожденный подграф. По этой причине, возможно, будет проще создавать порожденный подграф для потоков управления начиная от входов, а не от выходов. Однако мы имеем дело с моделя-
ми потока данных, и элементы потока управления встречаются здесь (по крайней мере, на это следует надеяться) лишь случайно. Ситуация показана на следующем рисунке. Начните создание порожденного подграфа так же, как и раньше, с выхода U (для каждого выхода). Он приводит в вычислительные области С1 и С2 и связан- ные с ними источники данных И и 12 (которые могут перекрываться). Продолжив создание порожденного подграфа, вы достигнете узла потока управления, кото- рый по определению означает, что за ним возможен только один из двух альтерна- тивных вариантов. То есть вы должны выбрать либо область С1, либо область С2 (и связанные с ними потоки данных). Каждый вариант порождает один тест. Для обоих тестов нужны выходы из области В и набор данных 14. Существует хорошая практика создания порожденных подграфов: 1. Для узлов выбора потоков данных начинайте создание порожденного под- графа с входящих в узел связей. 2. Для узлов потока управления начинайте создание порожденного подграфа с исходящих из узла связей. Выбор пути при тестировании потока управления заключается в выборе по- рожденного подграфа, начинающегося с узла BEGIN'. Создание порожденного подграфа при наличии потока управления в графе потока данных усложняется, поскольку в целом мы хотим создать порожденный подграф начиная с выхода. Однако присутствие узлов потока управления вынуждает нас менять направле- ние и исключать из порожденного подграфа то, что мы могли включить в него раньше (до того как осознали, что это был узел потока управления). Прежде чем вы станете это делать, проверьте, нужна ли вам часть модели с по- током управления. В предыдущем примере такой необходимости не было. Мы могли бы, например, заменить узел потока управления узлом выбора данных, ко- 1 Говоря формально, именно порожденный подграф определяется выбранным путем начиная от узла BEGIN и заканчивая узлом EXIT. То есть выберите путь, а затем создайте порожденный подграф, который объединяет другие порожденные подграфы, полученные для каждой активной переменной вдоль пути.
торый осуществлял бы выбор между выводами областей С1 и С2 и затем переда- вал бы их в область СЗ. Можете ли вы поступить подобным образом — зависит от приложения и от природы используемых объектов. Помните, что не важно, как именно может быть (или не может быть) запрограммировано приложение. Важно, насколько правильно модель отражает смысл требований. Вы ничего не можете сделать с основными (существенными) потоками управления и синхронизации. Вы можете лишь экспериментировать с каким-либо удобным примером. Если ра- зумно примененный в вашей модели узел потока управления устраняет дублиро- ванные потоки данных, то это хорошо. Если он прибавляет сложности и затрудня- ет построение порожденного подграфа, то это плохо. Случай 4: Смешение предикатов потока управления и узлов выбора потоков данных Этот случай — комбинация двух предшествующих ситуаций, так что будьте акку- ратны в построении ваших порожденных подграфов. Вам следует избегать сме- шанных моделей, поскольку в них легко запутаться. В отличие от программиро- вания, путаница приведет не к созданию ошибки, а к бесполезной трате времени и созданию бесполезных или невыполнимых тестов. Если у вас есть смешанная модель, как с узлами потока управления, так и с уз- лами выбора, вам лучше пометить узлы каждого типа, поскольку вы будете часто колебаться при построении порожденных подграфов. Случай 5: Циклы Модели потока данных просто неудобны для проверки циклов. Правильный под- ход — выполнить полную развертку однократного прохода цикла и затем ввести узел выбора данных для каждого значения Например, если вы предпочтете три варианта, у вас получится: отсутствие прохождения цикла, однократное прохож- дение, двукратное прохождение и узел выбора для этих трех случаев. 5.4.5. Итоговый пример Теперь создадим модель, которую мы можем использовать для активизации теста и для завершения этой главы. Она основана на бланке ИПС номер 1 (Форма 1040, Строка 23а/Ь). После небольшой переработки этого бланка, сделанной для того, чтобы придать ему более формальный вид, мы имеем следующую модель. У Вас У Вашего Супруга(и) С1: Мин ($2000. HnC_Contrib_1994 (Вклад_ ИПС_в_1994)) С2: Income (Доход) СЗ: Мин (Cl. С2) (выход) 1040 23а 1040 23b Неработающий(ая) супруг(а) С4: Мин (С2а. $2250) ________ С5: Выход_из_СЗ С6: Строка_5 - Строка_4 С7: Мин ($2000. 94_вклад_супр) _________ С8: Мин (Строка_6, Строка_7) (выход)
Я буду строить эту модель для случая, когда ваш супруг(а) (если он(а) есть) не работает, и вы можете (или не можете) внести взнос в ИПС за него. Полная мо- дель (в которую включен работающий супруг) оставлена в качестве упражнения для самостоятельного выполнения. Вы можете предположить, что в этой модели некоторые из узлов и связей на самом деле не нужны, например, такие как: С1а, СЗа, С4, С5 и С7. Я сохранил все узлы, следующие за узлом выбора, в качестве меры предосторожности и для того, чтобы быть уверенным в том, что узел выбора в этой модели явный, а не скрытый, по аналогии с формой. Строка 5 (узел 5) была сохранена, поскольку подобная строка имеется в форме ВНС, и у нас будет воз- можность проверить ее значение. kl: CCla константа » $2000 СС7 BCla: CCla ВХОД ваш_взнос_в_ИПС_94 С2а: ССЗа ВХОД your_94_wages (Ваша_заработная_плата_в_1994 ?? СС4а ВС7: СС7 ВХОД взнос_супруга_в_ИПС_94 к2: СС4а константа = $2250 CCla: Cla ВЫБРАТЬ мин minfkl, BCla) Cla: ССЗа ССЗа: СЗа ВЫБРАТЬ мин mintCla. С2а) СЗа: ВЫХОДа ВЫХОД в Строку 23а Формы 1040 СБ С5: С6 (замечание: спецификация ВНС неправильна, вместо "СтрокаЗ" должно быть сказано "СтрокаЗа" - подобные пустяки как раз и порождают ошибки) СС4а: С4 ВЫБРАТЬ мин (С2а. к2) (замечание: в этом месте еще одна ошибка ВНС) С4: Сб Сб: СС8 С4-С5 СС7: С7 ВЫБРАТЬ мин (ВС7. kl) С7: СС8 ВЫБРАТЬ мин (Сб. С7) СС8: С8 ВЫХОД в строку 23b формы 1040 Сначала мы выбираем простые порожденные подграфы. Одним из них являет- ся случай взноса в ИПС, вводимого в строку 23а формы ВНС 1040. Порожденный подграф, начинающийся от выходного узла ВЫХОДа, содержит узлы kl, BCla, CCla, С1а, ССЗа, C2a, СЗа, ВЫХОДа и соответствующие связи. Тут имеются два узла выбора (и предикаты), но только три возможности, зависящие от того, какая из следующих величин меньше: $2000, 1994 Взнос в ИПС, или заработная плата в 1994 году. В силу этого наш порожденный подграф приводит к трем тестовым ва- риантам, которые следует активизировать позже. Вывод в строке 8 для супружеского взноса в ИПС более сложен из-за того, что выбор этого вывода приводит к включению в наш порожденный подграф всего графа, за исключением узла ВЫХОДа. Я буду строить свои порожденные графы методично, двигаясь от конца к началу, и буду пытаться обеспечить покрытие свя- зей и узлов, не покрытых предыдущим тестовым вариантом. Получившиеся це- почки выглядят следующим образом. Тест 1: С8. СС8. Сб. С5. СЗа. ССЗа. Cla. CCla. BCla. С4. СС4а. к2 Тест 2: С8. СС8. Сб. СБ. СЗа. ССЗа. Cla, CCla. kl. С4. СС4а. С2а
Тест 3: С8. СС8. Сб. С5. СЗа. ССЗа. С2а. С4. СС4а Тест 4: С8. СС8. Сб. С5. СЗа. ССЗа. Cla. CCla. kl. С4. СС4а. к2 Тест 5: С8. СС8. С7. СС7. ВС7 Тест 6: С8. СС8. С7. СС7. К1 Заметьте, что я выписывал имена узлов, а не связей. В общем случае вы долж- ны выписать все связи или ясно показать, что вы определяете набор сегментов путей через граф потока данных, которые определяют порожденный подграф. Например, более точное представление будет таким: Тест 1: С8. СС8. Сб. С5. СЗа. ССЗа. Cla. CCla. ВС1а/Сб. С4. СС4а. к2 Я использовал сокращенную запись, поскольку в данном случае она недву- смысленна. В случае более сложного потокового графа она может быть неод- нозначной и для точной идентификации маршрута будет недостаточно просто пе- речислить имена узлов. Заметьте, что в отличие от тестирования потока управления, где мы следовали только вдоль одного набора стрелок, в данном случае, поскольку Сб содержит вы- числение, затрагивающее С4 и С5, нам следует включить в порожденный подграф обе связи. Для узлов выбора, однако, в порожденный подграф включается ветвь только для выбранной входящей связи. Может быть, и есть возможность обойтись меньшим количеством тестов, но я не слишком к этому стремился. Задача заклю- чается в том, чтобы обеспечить покрытие связей, а не минимизировать количест- во тестовых вариантов. Узлы выбора здесь коварны, потому что они основаны на сравнении двух величин, я имею в виду MIN (А, В). Если обе величины одинако- вы, вы не знаете, какую связь следует использовать, так что это не слишком хоро- шая основа для тестовых вариантов (по крайней мере, для попытки обеспечить покрытие связей). 5.4.6. Активизация Каждый тест соответствует порожденному подграфу. Если порожденные подгра- фы были определены корректно, тогда для активизации одного подобного порож- денного подграфа достаточно задать только его входные величины. Активизация происходит по большей части так же, как это было описано для потоков управ- ления, за исключением того случая, когда вы можете решить, что проще начать с выхода и двигаться в направлении входов. Если же в порожденном подграфе нет узлов выбора или узлов потока управления, об активизации не стоит и говорить. Любые приемлемые входные значения подойдут. В случае существования узлов выбора или узлов потока управления следует выполнить несколько процедур. 1. Обратите внимание на минимальные и максимальные значения для каж- дого входа. Если значения составляют некоторое множество, запишите все значения из него. 2. Двигайтесь по всем ветвям порожденного подграфа в обратном направле- нии (к началу), отмечая пути, которые достигают входов без прохождения через узлы выбора (потоков данных или потоков управления). Вы можете
пока игнорировать эти части порожденного подграфа, потому что для вхо- дящих данных, скорее всего, нет ограничений. 3. Двигайтесь наверх вдоль путей, пока не достигнете узла выбора (для кото- рого вы уже сделали выбор). Этот узел выбора — неважно является ли он узлом выбора потоков данных или потока управления — содержит преди- кат, значение которого вы уже определили (выбором данного порожденного подграфа). Этот предикат теперь накладывает ограничения на все входные значения, которые могут быть достигнуты при движении по порожденному подграфу из этой точки. Определите самый широкий набор входных значе- ний, удовлетворяющих этому предикату. 4. Продолжайте обрабатывать каждый встреченный вами предикат (при дви- жении к началу порожденного подграфа). Если в порожденном подграфе на выбранном пути имеется больше двух предикатов, следует рассматривать их условия одновременно, а каждый последующий предикат накладывает дополнительные ограничения на возможные входные значения. Для потоков данных активизация обычно происходит проще, поскольку в этом случае существует сравнительно немного промежуточных узлов и обычно не нуж- но интерпретировать предикаты для того, чтобы выразить их через входные пе- ременные. Если вы имеете дело с таким случаем, поступайте так, как если бы ра- ботали с потоками управления, учитывая, что вы имеете дело с порожденными подграфами для потоков данных, а не с отдельными путями. Активизация предыдущего примера с бланком ИПС не так уж сложна. Ваши взносы в ИПС сравниваются с $2000, и соответственно есть два возможных ва- рианта. Ваша заработная плата в 1994 году сравнивается с $2250 — вот еще два варианта. И, наконец, взнос в ИПС вашего супруга сравнивается с $2000. Всего мы получаем восемь возможных случаев, из них шесть должны быть осуществи- мы. Составляя различные комбинации входных переменных, выбирая их больше или меньше той суммы, с которой они сравниваются, получаем следующие набо- ры значений для активизации тестов: Тест Ваш 1994 взнос Ваша заработная плата в 1994 Ваш 1994 взнос Тест 1: $1900 $2251 $2060 Тест 2: $2050 $2100 $2251 Тест 3: $2100 $1950 $3500 Тест 4: $2100 $2251 $1500 Тест 5: $200 $1800 $1500 Тест 6: $200 $1800 $2500 Это не единственные значения, позволяющие обеспечить покрытие связей. но их легко получить. Заметьте, что я не стал брать значения констант равны- ми $2000 и $2250. Я сделал это для того, чтобы обезопасить себя от случайной корректности. Если бы я выбрал значения $2000 для взносов и $2250 для зара- ботной платы, тогда с некоторой вероятностью могло бы случиться так, что обе связи, входящие в узлы выбора MIN (А, В), могли бы иметь одинаковые значения. В таком случае ошибка в предикате не сыграла бы никакой роли, поскольку мы бы получили $2000, невзирая на возможную некорректность алгоритма вычис- лений.
5.4.7. Предсказание итогов Здесь не обсуждаются проблемы, касающиеся предсказания итогов, которые бы не рассматривались в главе 3. Однако вы вряд ли будете строить модель- ную программу на основе модели потока данных, потому что в большинстве языков программирования не слишком удобно проектировать потоки данных. Поскольку в вашей модели не должно быть очень много потоков управления, для построения оракула хорошо подойдет электронная таблица. Каждая ячейка таблицы — это явный узел, при этом она обеспечивает прямые отношения пото- ков данных между формулами в ячейках. Таблицы по своей природе являются удобным средством для работы с потоками, и так же, как и в случае графов по- тока данных, присутствие в них элементов потока управления сильно усложня- ет ситуацию. 5.4.8. Проверка соответствия пути Это не проверка путей как таковая, это проверка узлов. Вы не получите боль- шого преимущества от тестирования потоков данных и останетесь незащищен- ными от случайной корректности, если не будете проверять промежуточные вычисления, то есть, например, значения в узлах. Более эффективные методы тестирования подразумевают большую работу, а проверка этих промежуточных вычислений может оказаться очень трудоемкой. Таким образом, и для них вам нужен оракул. Под «тестируемостью» здесь понимается возможность проверить промежу- точные вычисления. Я не знаю, как это сделать без использования логических операторов проверки, заранее вычисленных выходных величин и символьных от- ладчиков. Одним из преимуществ объектно-ориентированного программирования явля- ется то, что, наряду с надлежащим сокрытием информации, минимизирована ве- роятность побочных эффектов, и результатом должна быть более устойчивая ра- бота системы. Но сокрытие информации не должно означать, что тестировщик действительно не имеет доступа к этим данным. Электрические системы в вашем автомобиле имеют разъемы, на первый взгляд не служащие никакой полезной цели. Вам они не нужны и не стоит экспериментировать с ними. Но спросите ва- шего механика, насколько важны эти тестовые разъемы. Подобным же образом материнская плата в вашем ПК имеет разъемы и перемычки, необходимые только для тестирования, и нужно быть смелым и глупым одновременно, чтобы играть с ними. Но для тестирования они действительно полезны. Тестирование — законное основание для доступа к так называемым собствен- ным данным и для снятия завесы, скрывающей информацию. Если вы тестируете ваше собственное программное обеспечение, используйте многочисленные логи- ческие операторы проверки как базовые точки тестирования. Если вы тестируете стороннее программное обеспечение, окажите на его разработчика максимально возможное давление, чтобы заставить внедрить нужные точки тестирования или логические операторы проверки.
5.5. Анализ приложений 5.5.1. Виды приложений Приложения охватывают почти весь спектр существующего программного обес- печения, но я бы не использовал тестирование потоков данных для низкоуровне- вого тестирования программного обеспечения, в котором имеется много необхо- димых потоков управления. Наиболее естественно использовать рассматривае- мый метод для следующих приложений: 1. Объектно-ориентированное программное обеспечение. ООПО — парадиг- ма, основанная на потоках данных, вот почему графы потоков данных час- то являются частью методологии разработки ООПО. Если вы используе- те для этой цели тестирование потоков данных, вы должны допускать, что объекты были должным образом протестированы на более низком уровне, так что вы можете не сомневаться в их надежности и заменить каждый из них соответствующим узлом. Далее вы концентрируетесь на том, правиль- ные ли объекты активизируются, правильные ли сообщения проходят, и так далее. 2. Тестирование интеграции. Главная пиоблема с интеграцией не в том, рабо- тают ли интегрированные компоненты (это должно быть проверено в ходе тестирования модулей), а в том, правильно ли они соединены и сообщают- ся друг с другом. Каждый компонент моделируется узлом, а граф потока данных может быть деревом вызовов функций программы. Это замечатель- но, поскольку у нас есть инструменты для отображения деревьев вызовов. Печально в данном случае то, что обычного дерева вызовов будет недоста- точно. Если имеются глобальные переменные, вы должны рассматривать потоки данных для них. И поскольку некоторые вызовы и межкомпонент- ные связи могут быть динамическими, статическое дерево вызовов, опре- деляемое компилятором/редактором связей, не даст вам полной картины — но это будет хорошим началом работы по ее созданию. 3. Электронные таблицы. Электронные таблицы максимально адаптированы к чистому языку моделирования потока данных. Не пренебрегайте элек- тронными таблицами, считая их лишь вспомогательным средством. Они представляют собой реальное средство программирования для людей, со- здающих сложные приложения для бизнеса, но имеющих мало инстру- ментов и методов для их проверки. Однако если вы покупаете готовые электронные таблицы и планируете придать толчок вашему бизнесу с их помощью, некоторое тестирование перед их полноценным использованием будет не лишним. 5.5.2. Предположения об ошибках Все ошибки, для поиска которых предназначено тестирование потока управ- ления, можно найти и при помощи тестирования потоков данных, посколь-
ку оно включает в себя тестирование потоков управления как составной эле- мент. Поскольку мы избегаем несущественных потоков управления в моделях потока данных, мы допускаем, что программисты умеют сами избавляться от простых ошибок потока управления. Это смещает акценты в сторону поиска ошибок данных. В моей систематике ошибок [BEIZ90] это ошибки 42хх. К по- добным ошибкам относятся ошибки исходных и конечных значений, ошиб- ки дублирования и искажения имен, перегрузка, неверный элемент, неверный тип, плохие указатели, аномалии потоков данных (например, закрытие файла до его открытия). 5.5.3. Ограничения и предостережения 1. Тестирование потоков данных не может быть лучше вашей модели. И оно не будет работать, если и вы не пооаботаете над несколькими типичными проблемами. 2. Вы все еще не нашли недостающие требования в спецификации. 3. Вы с большей вероятностью обнаружите неправильные характеристики программного обеспечения, если обеспечите проверку каждого вывода. 4. Тестирование потоков предпочтительнее использовать для выявления оши- бок на высоких уровнях интеграции. 5. Тестирование потоков данных может потерять эффективность в том слу- чае, если программное обеспечение и проектирование тестов выполнены одним и тем же человеком. К тестированию потоков управления это имеет меньшее отношение, поскольку принципы, лежащие в основе тестирования потоков данных и тестирования потоков управления, настолько различны, что одна только смена принципа, вероятно, приведет к новой перспективе, даже если речь идет об одном и том же человеке. 6. Вы по-прежнему можете не заметить случайную корректность, но ее веро- ятность легче оценить. 7. Ваши тесты не лучше, чем ваш оракул. 8. Тестирование потоков данных вряд ли вам поможет, если вы не нашли спо- соба проверить промежуточные узлы. 5.5.4. Автоматизация и инструментальные средства К концу 1994 года не существовало коммерческих сервисных программ, под- держивающих поведенческое тестирование потоков данных. Существует мно- го частных программ, поддерживающих структурное тестирование потоков дан- ных на С и Паскале [FRAN85, HARR89, HORG92, KORE85, KORE88, LASK90, OSTR91, WILS82], Если у вас есть средство проектирования, поддерживающее диаграммы потоков данных, справьтесь у продавца, почему оно не обеспечивает автоматизацию проектирования тестов.
5.6. Резюме Тестирование потоков данных — более эффективный метод, чем тестирование потоков управления. Он основан на определении модели потоков данных и ис- пользовании этой модели как основы для проектирования тестов. Тесты созда- ются путем выбора порожденных подграфов — движением от выходных узлов ко всем входным узлам порожденного подграфа. Мы определили несколько метрик покрытия, но метод всех использований, дополненный разверткой циклов (дву- кратной), рекомендован в качестве минимально приемлемой метрики. 5.7. Вопросы для самопроверки 1. Дайте определения следующих терминов; покрытие всех определений, покрытие всех путей определение - использование, покрытие всех узлов, покрытие всех предикатов, покрытие всех использований, логический опе- ратор проверки условия, управляющая входящая связь, удобное упоря- дочение, использование в вычислениях, граф потоков данных, порожден- ный подграф, узел выбора данных, предикат выбора данных, определять, необходимый цикл, необходимое упорядочение, значение входящей свя- зи, входной узел, покрытие ввода/вывода, значение сзязи, развертка цик- ла, необязательный цикл, значение исходящей связи, выходной узел, пусто, перегрузка, узел с предикатом, использование в предикате, узел обработки, псевдопеременная, запоминающий узел, подграф, использование. 2. Покажите, что строка 6 в бланке ИПС никогда не может быть отрицатель- ной как для работающего, так и неработающего супруга(и), так что в дан- ном случае необязательно проводить сравнение с нулем. Подсказка: опера- ция МИН — транзитивна. 3. Переделайте Бланк ИПС, включая логические потоки и потоки данных для случаев работающего и не работающего супруга. Выберите порожденный подграф, активизируйте его и разработайте тестовые варианты. 4. Создайте модели потока данных для формы 1040. Трактуйте данные, взя- тые из других форм, как входные переменные. Для каждого случая спроек- тируйте модель, выберите порожденные подграфы и разработайте тестовые варианты, используя покрытие ввода/вывода, покрытие узлов и стратегию всех использований. Проверьте вашу работу, используя налоговый пакет или электронную таблицу в качестве оракула. Вы можете переписать нало- говый пакет и взять входные значения из других форм, (а) строки 1-6, (б) строки 7-22, (в) строки 32-40, (г) строки 41-46, (д) строки 47-53, (е) стро- ки 54-60, (ж) строки 61-65. 5. То же, что и задание 4. Форма 1040, Бланк SE, краткая форма, строки 1-6, но задействуйте логику, чтобы определить, может ли быть использована крат- кая форма. Используйте граф только потоков данных, затем проделайте то же самое с использованием модели графа потоков управления и покрытием
условий предикатов и переделайте задание, используя смесь модели пото- ков управления и модели потоков данных. 6. Форма 1040, бланк на строке 10. Полная форма. 7. Форма 1040, бланк на строке 22, social security income (выплаты по социаль- ному страхованию). Полная форма. 8. Форма 1040, бланк на строке 34, dependent deductions (льготы иждивенца). Полная форма. 9. Форма 2106, только транспортные расходы. Рассмотрите случай только од- ного транспортного средства. Включите разделы А, В и С, но не D, и исклю- чите строки 1-10. 10. Форма 2688, Application for Extension to File (Заявление о продлении сро- ка). Форма целиком. И. Форма 2210, Неполная оплата налогов, (а) только строка 1, (б) часть II, (в) часть III, (г) часть IV, раздел А, (д) часть IV, раздел В. Предположите, что вы можете использовать краткий метод (Часть III) в случае, если не сде- лали отметок в графах 1b, 1с, или Id. Во всех случаях выводы (если таковые имеются) идут в соответствующую строку Формы 1040. То есть не заботь- тесь о Формах 1040А, 1040NR, 1041 и так далее. 12. Смоделируйте часть IV формы 2210 как граф потоков управления с детер- минированным циклом и протестируйте его соответствующим образом. 13. Представьте форму 2210 целиком в виде графа потока данных с одним уз- лом для каждой из частей II, III, IVA и IVB. Моделируйте часть I по своему усмотрению, но следите за тем, чтобы высокоуровневая модель правильно определяла, когда надо использовать часть III. 14. Проделайте задание 4 для формы 3903 целиком, Employee Moving Expenses (Расходы служащего на передвижение).
Тестирование потоков транзакций 6.1. Обзор Графы потока транзакций используют в системном тестировании приложений, работающих в режиме онлайн, и программного обеспечения для пакетной обра- ботки. Этот граф обладает свойствами как потока управления, так и потока дан- ных. 6.2. Основные термины Внешние термины: поглощать, подтверждать прием, приложение, архивные дан- ные, аудит, пакет, вызов, емкость, проверка, код, коммуникации, конкатенация (объединение), параллельный, аварийный отказ, данные, база данных, блок дан- ных, ошибка в данных, регистрация данных, отлаживать, проектировать, драйвер устройства, диагностика, дискретный, динамический, ошибка, глобальные дан- ные, иерархия, входящий, инициализировать, ввод, ошибка ввода, целое число, установка, интерфейс, логика, модель, неединичпый вход, неединичный выход, многозадачность, сеть, операционная система, выходной, раздел, эффективность, приоритет, распределение вероятности, обработка, узел обработки, программа, программист, язык программирования, протокол, запрос, очередь, случайный, прием, запись, восстановление, сброс, ресурс, маршрутизация, сценарий, обеспе- чение безопасности, последовательность, сервер, имитатор, синхронный, мгновен- ная запись, программное обеспечение, сортировка, ключ сортировки, стек, подпро- грамма, система, задача, среда тестирования, временная отметка, след, значение. Внутренние термины: ветвление, свободный от ошибок, компонент, тестиро- вание компонентов, составной предикат, поток управления, поток данных, на-
чальный узел, конечный узел, модель конечного числа состояний, граф, входящая связь, ввод, интеграция, промежуточный узел, связь, покрытие связей, вес связи, цикл, тестирование цикла, модельная программа, узел, покрытие узлов, итог, ис- ходящая связь, путь, предикат, отношение, активизировать, порожденный под- граф, спецификация, состояние, субмодель, системный тест, проект теста, путь теста, тестирование, критерий соответствия. Транзакция — единичная операция по обработке данных. Маркер транзакции — метка (например, точка), которая отображает присут- ствие транзакции на модельной связи. Контрольная запись транзакции — гипотетическая или фактическая запись, кото- рая содержит данные о транзакции. В фактической записи нет необходимости, одна- ко во многих системах она присутствует. Там, где контекст позволяет, вместо термина «контрольная запись транзакции» будет использоваться термин «запись транзакции». Состояние транзакции — потенциально это значения всех данных в контроль- ной записи транзакции или ее неявном эквиваленте. Но, как правило, состояние выражают лишь частью данных записи, зачастую целым числом. Тип транзакции — некое обозначение, например, целое число, которое исполь- зуется для идентификации транзакций различных типов Стартовый узел — узел в модели графа потока транзакций, в котором транзак- ция начинает нас интересовать. Это входной узел графа потока транзакций. Завершающий узел — узел в модели графа потока транзакций, в котором транзак- ция прекращает нас интересовать. Это выходной узел графа потока транзакций. Задача — каждая задача в графе потока транзакций представлена узлом. Узел ветвления — узел, в котором входящая транзакция выбирает одну из не- скольких альтернативных исходящих связей. Так, на рисунке входящая транзак- ция вышла на самую верхнюю связь. Предикат ветвления — предикат, который управляет выбором одной из исхо- дящих связей узла ветвления. Он может быть основан на значениях данных тран- закции (то есть значениях в управляющей записи транзакции) или же на комби- нации типа и состояния транзакции. Управляющая входящая связь — по возможности не зависящая от значений в записи входящая связь, которая определяет, какая из исходящих связей узла ветвления будет выбрана транзакцией. Узел ветвления с управляющей входящей связью подобен железнодорожной стрелке (то есть «направляет»). Для каждой управляющей входящей связи должен существовать ассоциированный с нею пре- дикат. Управляющие входящие связи обозначены пунктирными линиями.
Узел соединения — транзакция, поступающая по любой из входящих связей узла пересечения, выйдет по единственной исходящей связи этого узла соедине- ния. Это то же самое, что и соединительные узлы пересечения в графах потоков управления. Узел порождения — узел, в котором входящая транзакция генерирует более чем одну исходящую транзакцию. На рисунке входящая транзакция (материн- ская) произвела дочернюю транзакцию. Дочерние транзакции имеют индивиду- альные свойства, которые могут быть (частично) унаследованы от родительских транзакций. Мать * Дочь® Узел расщепления — узел, в котором входящая транзакция (материнская) ге- нерирует дочерние транзакции, а сама прекращает свое существование. Дочерние транзакции не должны быть идентичными. Предполагается, что каждая из них имеет свои собственные свойства, например, тип и состояние. Дочь ® Дочь® Узел слияния — узел, в котором две или более входящие транзакции (родитель- ские транзакции) сливаются в новую, выходящую дочернюю транзакцию. После узла слияния родительские транзакции перестают существовать. @Родитель Дочь ® Родитель Узел поглощения — узел с входящими транзакциями, одна из которых (хищ- ник) поглощает другие (жертвы).
• Хищник @ Жертва Хищник Марковский узел — узел, действие которого (обработка, ветвление, порожде- ние, расщепление и т. д.) зависит только от типа и состояния входящих транзак- ций, но не от пути, по которому транзакция добралась до узла. Марковский граф потока транзакций — граф потока транзакций, все узлы ко- торого являются марковскими. 6.3. Отношения и модель 6.3.1. Основы Материал, рассматриваемый в этом разделе, описывался также в [MURA89, РЕТЕ81]. Объекты {узлы) — шаги процесса обработки данных посредством транзакций, например, шаги программы. Узлы представляют собой интересующие нас дей- ствия, которые трансформируют входящие транзакции и производят выходящие транзакции и/или меняют состояние входящих транзакций. Узлы могут модели- ровать не только программы, но и действия людей, сетевые операции и вообще все, что имеет смысл. Предполагается, что узлы имеют свою собственную модель, будь то модель потока управления, модель потока данных или какая-нибудь еще мо- дель. Производимое обрабатывающим узлом действие зависит только от данных, содержащихся в записях входящих транзакций. Считается, что модели обработки транзакций являются марковскими. Объекты (транзакции) — транзакция идентифицируется своей контрольной записью (фактической или гипотетической). Эта запись содержит по меньшей мере тип и состояние транзакции. Предполагается, что и все другие интересующие нас данные содержатся в записи транзакции. Интерпретация данных в записи транзакции не зависит от значений в любой другой записи транзакции. Отношение (связи): «Непосредственно следует» — соединение узлов А и Б свя- зью от А к Б, если выходящая из А транзакция обрабатывается затем узлом Б. Вес связи — с любой связью может быть ассоциировано несколько маркеров транзакций. Каждый маркер представляет одну транзакцию. Мы будем моделировать часть обработки формы 1040, как если бы она была сделана добропорядочным налогоплательщиком, который настаивает на том, что- бы каждая операция совершалась в том же самом порядке, в каком она появля- ется в форме. Внутренняя налоговая служба в США не предъявляет такого тре- бования, и вы можете заполнять формы в том порядке, в каком это имеет смысл, но такое поведение не слишком применимо к моделированию потока транзакций. (Для этого больше подходят модели потока данных.) Заметьте, что сейчас мы мо- делируем не компьютер или программу, хотя и могли бы. Мы моделируем, каким
образом Видения Вистерия (наш субъект) заполняет декларацию о подоходном налоге. 11: 12: Предыдущий шаг в модели 12: 13: НЕ узел ветвления (имеется коммерческий доход?) 12.1: ДА 12.1: 12.2: узел порождения. 1040 продолжается С: дочерняя транзакция, для обработки Бланка С С: 12.2: заполненный Бланк С (узел расщепления) С-фин: заполненный Бланк С для налоговой службы 12.2: 13: узел поглощения, данные Бланка С поглощаются 1040 13 ... узел 13 - это узел соединения Узел 12 является узлом ветвления, так как транзакция должна либо продол- жить заполнять Бланк С, либо обойти его, если нет дохода от индивидуальной трудовой деятельности. Узел 12.1 — это узел порождения, из которого начинает- ся дочерняя транзакция для Бланка С. Предположим, что на этом уровне в узел С приходит незаполненный Бланк С, а выходит из узла С уже заполненный. Узел 12.2 представляет собой узел поглощения, потому что здесь данные Бланка С за- носятся в форму 1040. Узел С — узел расщепления, так как нам необходима копия Бланка С для налоговой службы, а также для формы 1040. Наконец, узел 13 явля- ется узлом соединения, потому что форма 1040 может появиться на любой из вхо- дящих в него связей, но не на обеих. 6.3.2. Маркировки Маркировка. Набор всех меток (и связанных с ними состояний) на всех связях в любой момент времени называется маркировкой графа потока транзакций. Для всего графа потока транзакций маркировка является тем же самым, чем является состояние для отдельной транзакции. Очередь. Связь, которую можно маркировать более чем одной меткой, пред- ставляет собою очередь. Это может, конечно, быть и обрабатывающая очередь, но она может также представлять собой и обычную очередь из ожидающих людей. Проследим путь следования одной транзакции через граф потока транзакций. Если бы не существовало узлов расщепления и порождения, это было бы эквива- лентно маркировке пути в графе потоков управления. Но две детали делают эту простую интерпретацию маловероятной — существование очередей и узлы слия- ния и поглощения. Мы можем использовать различные маркировки, определяя, какие маркеры и на каких связях появляются на каждом шагу. В нашей модели есть два вида сим- волов: форма 1040 и Бланк С, сокращенные до «Ф1040» и «Б-С» соответственно. Если в модели есть только одна транзакция, то существуют две возможные марки- ровки в зависимости от того, выполняем ли мы Бланк С. Без Бланка С: Шаг 1: 11/12 Ф1040 Шаг 2: 12/13 Ф1040 С Бланком С: Шаг 1: 11/12 Ф1040
Шаг 2: 12/12.1 Ф1040 Шаг 3: 12.1/12.2 Ф1040. 12.1/С Б-С Шаг 4: 12.1/12.2 Ф1040. С/12.2 Б-С. С/С-фин SC-C Шаг 5: 12.2/13 Ф1040. С/С-фин Б-С Предположим, что дети Видении ведут свой собственный бизнес, а Видения заполняет за них налоговые декларации. Ее дети вносят данные в свои индиви- дуальные Бланки С, если это необходимо, а она заполнит за них всех формы 1040. Формы 1040 инициируются в узле И (только для этой подмодели). Они поступа- ют в узел 12, который обрабатывает Видения. Она решает, необходим ли Бланк С. У Видении много других дел, поэтому она может и не принять это решение немед- ленно. Следовательно, на входящей связи узла 12 накапливается очередь из форм 1040. Когда у Видении появляется время, она помещает те формы 1040, которым не нужен Бланк С, в очередь к узлу 13. А для тех форм 1040, которым действи- тельно необходим Бланк С, она берет пустой бланк С, заносит туда имя ребенка и помещает его в очередь Бланка С (12.1/С). Обработка Бланка С осуществляет- ся детьми Видении. Заполненные Бланки С поступают в очередь к С/12.2, откуда Видения забирает их путем переноса данных в подходящую форму 1040. На связи 12.1/12.2 также накапливается очередь. Число маркеров на любой из связей потенциально бесконечно, а, следователь- но, и число потенциально разных маркировок для всего графа потенциально бес- конечно. Хотя у Видении, как кажется, бесчисленное число детей, она имеет чуть ли не безграничное терпение, поэтому для нее это не проблема — но не для нас. В идеале нам следует тестировать графы потока транзакций для всех возможных пометок. Практически же это невозможно, поэтому всегда следует искать опреде- ленный компромисс. 6.3.3. Очереди Детальное описание очередей можно встретить в [СООР81]. Все реальные очереди ограничены, то есть они имеют некий максимально воз- можный размер. При выходе за пределы этих размеров плохо протестированные системы могут неожиданно выйти из строя, так что стоит тестировать максималь- но возможный размер очереди. Если существует очередь, то должно быть и прави- ло упорядочения — то есть правило, определяющее, в каком порядке транзакции будут поступать из очереди для обработки. Ниже приведены некоторые распро- страненные правила. Правило FIFO — «первым пришел — первым вышел» («first-in, first-out»), на- зываемое также «First-Come-First-Served» — («первым прибыл — первым обслу- жен»). Транзакция, которая раньше всех поступила в очередь, будет обработана раньше всех. Это самое простое правило очень распространено. Но представьте, что было бы, если бы Видения настаивала, чтобы все заполненные Бланки С воз- вращались к ней в том же порядке, в каком она отдавала их на обработку. Правило LIFO — «последним пришел — первым ушел» («last-in, first-out»), называемая также LCFS «Last-Come-First-Served» — («последним пришел — первым обслужен»). Транзакция, которая позже всех поступила в очередь, будет обработана раньше всех. Подобная очередь является обрабатывающим стеком,
в котором входящие транзакции помещаются на вершину стека и удаляются с вершины. Пакет. При возникновении определенных условий, таких как определенное число транзакций в очереди, или же в оговоренный момент времени обрабатыва- ются все транзакции в очереди в пакетном режиме. При этом во время обработки новые транзакции накапливаются в новой очереди. Случайное обслуживание. Обслуживание осуществляется случайным обра- зом — возможно, на основе вероятностного распределения по некоторой величи- не в контрольной записи транзакции. Очередь по приоритету. Каждая транзакция имеет свой приоритет. Этот при- оритет может быть фиксированным или зависеть от свойств транзакции, на- пример, от ее возраста. Каждая группа транзакций с данным приоритетом обра- батывается как отдельная очередь, причем очередь с наибольшим приоритетом обрабатывается первой. Внутри отдельной группы транзакций с данным приори- тетом сервис может осуществляться по принципу FIFO, LIFO и т. д. Множественная обработка. Для обработки очереди может использоваться один сервер {односерверная очередь) или несколько серверов {многосерверная очередь). Кроме правила упорядочения конкретной очереди, может существовать правило выбора сервера. Например, в супермаркете можно выбрать, в какую из очередей к кассам встать. В билетной кассе аэропорта, на почте, в банке нужно сто- ять в основной очереди и ожидать обслуживания до тех пор, пока работник учреж- дения не скажет «Следующий!» Далее термин простая очередь будет использоваться для обозначения односер- верной очереди без приоритета, обслуживаемой по принципу FIFO. Если правило упорядочения не оговорено, то наиболее вероятно, что это простая очередь. За ней следует очередь, обслуживаемая по принципу FIFO в зависимости от приоритета. Очередь с данным приоритетом обрабатывается по принципу FIFO, но первой об- рабатывается очередь с наибольшим приоритетом, затем очередь с более низким приоритетом и т. д. Если вы имеете дело с очередью, не являющейся простой, то убедитесь, что очередность приоритетов и, если необходимо, правило выбора сер- вера реализованы правильно. 6.3.4. Слияние и поглощение Существование узлов слияния и поглощения создает дополнительные проблемы при тестировании. Становятся необходимыми тесты синхронизации. Чаще всего возникают новые проблемы и вопросы, которые следует себе задать. 1. Правильные ли типы транзакций объединились? 2. В случае двух транзакций А и В, которые объединяются (или для А, погло- щающей В), появляются пять дополнительных ситуаций, которые необхо- димо протестировать: ® А приходит, а В — никогда не приходит (А). • В приходит, а А — никогда не приходит (В). • А приходит раньше В (А, В).
« В приходит раньше А (В, А). ♦ Обе транзакции приходят одновременно (то есть в пределах оговорен- ного времени) (АВ). 3. Правилен ли тип выходящей транзакции? Для поглощения это хищник, а для объединения — дочерняя транзакция. При тестировании необходимо рассмотреть каждый из этих случаев. Для узла слияния, имеющего три связи, потребуется протестировать 25 возможных вариан- тов. Для обозначения одновременных входов транзакций в узел слияния мы бу- дем использовать совместное написание, а для раздельных — запятые. Например, (АВ, С) означает, что А и В приходят в узел одновременно, а за ними следует С. Необходимо рассмотреть 25 тестовых вариантов. Ниже следуют тестовые вариан- ты для поглощения или слияния, в котором участвуют три транзакции. Каждая транзакция по отдельности: (А). (В), (С). Две транзакции за раз: (А, В), (А, С), (В, С), (В, А), (С, А), (С, В), (АВ), (АС), (СВ). Три транзакции за раз: (А, В, С), (В, А, С), (С, А, В), (А, С, В), (В, С, А), (С, В, А), (А, ВС), (В, АС), (С, АВ), (ВС, А), (АС, В), (АВ, С), (АВС). Число необходимых тестов быстро возрастает для узлов слияния с нескольки- ми объединяющимися транзакциями. Проектирование тестов легко автоматизиро- вать, но трудно заставить транзакции приходить в определенные узлы в определен- ном порядке. Так как слиянию и поглощению подвергаются чаще всего транзакции, которые уже прошли через какие-то операции обработки, в отличие от транзакций, пришедших извне, то выполнение этих тестов практически невозможно. 6.3.5. Циклы С одной стороны, циклы в потоках транзакций строго говоря, создают проблемы. А с другой стороны, они встречаются редко, и если встречаются, то они просты и встре- чаются нечасто. Цикл, который чаще всего можно обнаружить в потоке транзакций, — это цикл повторения обработки после обнаружения ошибки ввода данных. Так, на- пример, банкомат дает вам три попытки ввода вашего личного идентификационного номера. Можно ожидать, что похожие циклы повторения будут встречаться в боль- шинстве интерфейсов, таких как каналы связи с другими системами, драйверы уст- ройств и т. д. Очереди, обслуживаемые как пакет, очевидно, содержат цикл для обра- ботки пакетов. Сходным образом каждый узел обработки, обслуживающий очередь, работает в составе цикла для того, чтобы обрабатывать каждый последующий элемент в очереди и продолжать работу далее. Таким образом, он активируется каждый раз до тех пор, пока очередь не иссякнет. Такие циклы следует тестировать отдельно для каж- дого узла обработки на более низком уровне интеграции и тестирования. А это означа- ет, что необходимо выполнять тестирование циклов различных узлов обработки тран- закций в контексте компонентного тестирования этих узлов обработки. 6.3.6. Фокус и иерархические модели Модель потока транзакций можно использовать при различных степенях дета- лизации, вплоть до кода. Однако создавать модели потока транзакций на уровне
исходного кода — отнюдь не самая лучшая идея. Узлы на графах потока транзак- ций могут представлять собой не только действия программного обеспечения. Термин «обработка данных» был использован в общем смысле для обозначения любого вида работы с данными, вне зависимости от того, выполняется ли эта ра- бота компьютером, людьми или другими системами. Модель потока транзакций обычно используется как высокоуровневая модель. Наиболее часто ее используют в системном тестировании. Корректную работу компонентов следует проверить при компонентном тестировании, обычно это делают на предшествующей стадии интеграции. Разделение сложного действия на компоненты представляется в мо- дели потока транзакций лишь выборочно. Но при этом следует учитывать неко- торые детали. 1. Компоненты модели имеют интерфейсы, через которые происходит переда- ча данных. Обратите внимание, что глобальные данные могут соответство- вать этому требованию. 2. Компоненты могут взаимодействать только через свои интерфейсы. Если есть такие компоненты, сгруппируйте их и моделируйте группу как отде- льный объект. 3 Поведение компонента определяется типом и состоянием транзакции. 4. Поведение узла обработки не зависит от предыстории транзакции, если только предыстория не влияет на тип и состояние транзакции. Отдельный процесс должен быть марковским. 5. Можно проверить корректность поведения узла обработки путем проверки выходящих транзакций (или их контрольных записей) каждого процесса в модели. 6. При наличии соответствующих средств тестирования можно полностью протестировать один компонент в отдельности. При тестировании потока транзакций первоочередное внимание следует об- ращать не на корректную работу отдельных процессов, а на систему в целом. Особенное внимание следует уделять корректности интерфейсов между компо- нентами, корректности маршрутизации транзакций между компонентами, орга- низации и дисциплине очередей (если это не правила упорядочения FIFO), узлам слияния, поглощения, расщепления и порождения, синхронизации, одновремен- ности, созданию и уничтожению транзакций, а также дублированию и потере транзакций. 6.4. Методика 6.4.1. Основы Предположим, что у нас нет циклических транзакций. Если же вы встретите такие, будем надеяться, что их применение в данном случае является обоснован- ным, и их можно протестировать в пределах субмодели, включающей цикл. Для
любых циклов, которые невозможно обработать на более низком уровне, нужно будет использовать методики тестирования циклов, описанные в главе 4. 1. Проверьте спецификацию. 2. Идентифицируйте и дайте имя всем транзакциям, которые должна обра- ботать система. У вас не должно возникнуть проблем с «нормальными» транзакциями, так как они все должны присутствовать в спецификации. Трудности обычно возникают с транзакциями, которые подразумеваются в спецификации, но не сделаны явными. Ниже приведены примеры транзак- ций, которые часто пропущены в спецификациях, но должны присутство- вать в вашей модели. • Подтверждения о приеме, уведомление, отрицательное квитирование. • Специальные транзакции для установки и отладки. • Специальные транзакции для диагностики действий. • Транзакции, выполняющие аудит других транзакций. • Транзакции, используемые в режиме обучения персонала. • Транзакции инициализации или перенастройки для всех внешних ин- терфейсов. • Транзакции, используемые при восстановлении системы. • Транзакции, используемые для измерения характеристик системы. • Транзакции, используемые для проверки обеспечения безопасности сис- темы. • Транзакции, используемые в протоколах, не упомянутых выше. • Транзакции, используемые для запроса о статусе других транзакций. • Ответы на запросы о статусе транзакций. • Транзакции, создаваемые вашей системой для восстановления других транзакций. • Транзакции восстановления, полученные из внешних систем. 3. Определите иерархию типов транзакций, которая включает все транзакции, описанные выше в пункте 2. Как правило, вы можете использовать ту же ие- рархию, что и разработчики. Такой подход делает коммуникации проще. 4. Определите состояние транзакции для каждого типа транзакции. Состояния должны соответствовать последовательности обработки, присущей типу транзакции. Если состояния представляют собой простую последователь- ность пунктов, например «шаг 1, шаг 2, шаг 3,... выход», то достаточно будет просто составить список. Если есть признаки более сложного поведения, то вам, вероятно, будет необходимо использовать модель с конечным числом состояний (см. главу 9). 5. Определите поведение транзакции в любой момент ее жизненного цик- ла. Как она порождается (или поступает в систему), как завершается (или 6 Заг. 770
выходит из системы), как происходит операция слияния (и с кем), как пог- лощается, расщепляется, порождает другую транзакцию и т. д. 6. Определите гипотетическую контрольную запись для каждого из типов транзакций. Запись должна отображать по меньшей мере тип и состояние транзакции. При этом в большинстве систем по обработке транзакций вы должны быть в состоянии использовать действительную контрольную за- пись транзакции, реализованную в программном обеспечении. Для внешних транзакций, — таких как, например, транзакции, обрабатываемые другими системами или людьми, — вам необходимо будет определить подходящую гипотетическую запись. 7. Идентифицируйте все очереди. Определите для каждой очереди источник (источники) появления транзакций, правило их упорядочения, приоритеты в пределах одного правила, а также применяемую обработку. Протестируйте ограничения всех очередей, которые имеют ограниченные максимально возможные размеры. « Каким образом отдельные элементы помещаются в очередь? ♦ Каким образом отдельные элементы удаляются из очереди? • Какая модель очереди используется — односерверная или многосервер- ная? Если многосерверная, каково правило выбора сервера? 8. Идентифицируйте компоненты обработки (это не обязательно должно быть программное обеспечение). Сгруппируйте компоненты в соответствии с принципами, описанными выше в разделе 6 3.6. Возможно, потребуется переопределить типы транзакций, выполнить слияние типов транзакций, удалить очереди и т. д„ если этот этап моделирования приводит к необхо- димости группировки нескольких компонентов для того, чтобы удовлетво- рить критериям раздела 6.3.6. 9. Для каждого из определенных на предыдущем этапе компонентов реши- те, каким образом вы будете тестировать отдельные компоненты. По своей внутренней структуре каждый компонент может представлять собой дру- гую — модель потока транзакций более низкого уровня или же модель ино- го вида. 10. Несмотря на то, что реальные компоненты не обязательно действуют по- добным способом, отделите расщепления/порождения и слияния/погло- щения от связанных с ними узлов обработки путем помещения явного узла расщепления/порождения после обрабатывающего узла и явного узла сли- яния/поглощения до обрабатывающего узла. И. После выполнения предыдущих пунктов у вас должен быть набор узлов и связей, определяющих полный набор потоков транзакций, которые необхо- димо протестировать. 12. Верифицируйте модель, используя модельную программу, написанную на удобном языке программирования. Это может оказаться эффективным в моделях потока транзакций, потому что они чаще всего достаточно велики.
Типичная система по обработке транзакций содержит много простых транз- акций. Говоря «много», я подразумеваю «тысячи». Говоря «простые», я под- разумеваю, что ветвления, соединения, расщепления, порождения, слияния и поглощения очень редки. 13. Определите пути прохождения ваших тестов. Вы можете использовать как отдельные пути в графе, так и порожденные подграфы. Действуйте точно так же, как и при использовании других методик. 14. Активизируйте порожденные подграфы. 15. Предскажите итоги. 16. Определите критерий соответствия. 17. Выполните тесты. 18. Подтвердите итоги. 19. Проверьте значения во всех промежуточных узлах. 6.4.2. Иерархия покрытия Как и везде, в этой технике тестирования существует набор практических крите- риев покрытия, от самых простых (наименее трудоемких и неэффективных) до наиболее эффективных (основательных, но трудоемких). 1. Покрытие ввода/вывода и порождения/завершения. Проведите достаточ- ное число тестов и убедитесь, что все старты и порождения транзакций были осуществлены и что были созданы все исходящие транзакции (в том числе порожденные в данной системе). Эти тесты могут показаться слиш- ком слабыми, однако многие системы не проходят даже их. Рассмотрите все типы транзакций, о которых шла речь выше в разделе 6.4.1 (а также те спе- цифические транзакции, о которых я не говорил, но которые существуют в вашем приложении). Это тот минимум, который может сделать разум- ный человек. Исходя из здравого смысла, это эквивалентно гарантии того, что каждая строка кода была протестирована на уровне компонентов. Если кто-то полагает, что в тестировании типа транзакций нет необходимости, то он либо уверен, что транзакция не содержит ошибок, либо считает, что она вообще не нужна. Если она не нужна, уберите ее, и у вас будет на один ис- точник ошибок меньше. Наиболее редко используемые транзакции содер- жат больше всего ошибок. Дурную славу в этом отношении имеют транзак- ции, связанные с восстановлением. 2. Покрытие узлов. Покрытие узлов само по себе тоже не имеет смысла, по- скольку оно только еще раз подтверждает выводы, сделанные при тести- ровании модели более низкого уровня, например, в ходе тестирования компонентов. Покрытие узлов — это все же лучше, чем ничего, так как мы убеждаемся, что все порождения, расщепления, слияния, поглощения и об- работки в очереди транзакции ведут себя корректно. Этой проверки также могут не пройти многие системы.
3. Покрытие связей. Используя тесты, обеспечивающие покрытие связей, мы проверяем не только корректность отдельных узлов, но и их взаимодей- ствие друг с другом. Без покрытия связей тестирование системы будет не- полным. Обеспечивая покрытие связей, мы убеждаемся не только в том, что все транзакции корректно обрабатываются (покрытие узлов делает это за нас), но и в том, что на каждом шаге обрабатываются именно те транзакции, которые и должны. 4. Порожденные подграфы. Понятие порожденного подграфа в этом контексте практически полностью совпадает с аналогичным понятием для потока дан- ных (см. главу 5). Если существуют только узлы ветвления и соединения, то порожденный подграф соответствует пути «вход - выход» в созданной мо- дели. Если существуют узлы порождения или расщепления, то порожден- ный подграф получается путем следования по всем связям, исходящим из узла порождения или расщепления и дальнейшего следования по пути про- хождения этих транзакций до завершающего узла. Если существуют узлы слияния или поглощения, то порожденный подграф получается при следо- вании вдоль входящих связей до точки, где сливающиеся транзакции (или хищник/жертва) порождаются или входят в систему. Более подробно мы будем говорить о порожденных подграфах в разделе 6.4.4. 6.4.3. Построение модели Я бы предпочел построить модель потока транзакций для налоговой декларации, но, поскольку в процедуре заполнения налоговой декларации отсутствуют транз- акции, такая модель не подходит. Возможно, лучшим выбором в данном случае будет модель потока данных. Однако для того, чтобы использовать налоговые формы в максимально возможном числе упражнений и чтобы показать вам, что почти любую модель можно использовать в любом приложении, я буду модели- ровать Employee Business Expense (Бизнес расходы наемного служащего), форма 2106. Я буду рассматривать каждый вход или группу входов так, как если бы они были транзакциями. Pal: Сба Данные об основных расходах наемного служащего обрабатываются как единая транзакция, состоящая из: строки 2 (parking, tolls (парковка, подорожныйсбор)). строки 3 (travel, excluding meals and entertainment (командировочные расходы, исключая питание и развлечения)), строки 4 (other business expenses excluding meals and entertainment (другие бизнес расходы, исключая питание и развлечения)), строки 5 (meals and entertainment (питание и развлечения)). Это входящая транзакция, то есть транзакция из узла зарождения. Oil: CH General vehicle data (Данные об основных транспортных расходах), в том числе данные из строк 11. 12. 13. 15. 18. 19. 20 и 21. Транспортных средств может быть более одного, поэтому в этом стартовом узле может быть от 1 до п маркеров. Для каждого внесенного транспортного средства нужен один из них. Фр1: С23 Actual expenses (Фактические расходы), в том числе введенные в строки 23. 24а. 24b и 25. Вам не нужны эти данные, если вы решили использовать стандартную плату за перевозки. Тем не менее, вы
можете выбрать фактические расходы. Для этого стартового узла у вас могут быть значения от нуля до п. Это число может быть меньше, чем для 0т1. но не может быть больше. Ам1: СЗО Depreciation (Амортизация). Сюда входят данные из строк 30. 31. 33 и 36. Этот стартовый узел не может иметь больше маркеров. чем Фр1. поскольку вам не обязательно эксплуатировать все ваши транспортные средства. Ф1: Ф1а Стартовый узел с незаполненной формой 2106 (за исключением name, social security number, occupation (имени, номера социального страхования и рода деятельности)). Эта форма будет обработана и отослана обратно, на строку 20 бланка А. где она и возникла. Ф1а: С1 Ф1а - узел ветвления, в нем делается выбор О будут обрабатываться транспортные расходы или не будут. (С1) здесь сответствует ветке НЕТ. Транзакции в форме 2106 могут пойти либо по этой ветке.либо по ветке Ф1д. не не по двум одновременно. Ф1д Это ветка ДА. соответствующая наличию хотя бы одного транспортного средства. Cl: Сба С1 - это узел соединения, в который приходит либо транзакция 2106 из узла Ф1а (нет транспортных расходов), либо из узла Т1 (транспортные расходы заполнены). Сба: СЮ Узел поглощения, в котором поглощаются данные об основных расходах наемного служащего (Pal). Форма 2136 является хищником, a Pal - жертвой и Pal перестает существовать. СЮ: Выход (прохождение транзакции обратно в бланк А). Ф1д: Clla СПа - это узел порождения, где вы даете начало необходимому числу транзакций: по одной на каждое транспортное средство. Т1 Место, в котором вы. пройдя форму 2106. ожидаете vehicle deduction (налоговых льгот на транспортное средство). Tl: Cl Т1 - это узел поглощения, в котором налоговые льготы на транспортное средство вводятся в форму 2106. Тсум Т1 Тсум - это узел, в котором сливаются данные обо всех транспортных средствах. СПа: Тсум Детали, оставленные для вас в качестве упражнения (2). Модель содержит соответствующие пояснительные примечания. СИ, СПа и СЗО — это строки во вспомогательной модели, в которой выполняется большая часть обработки данных. На уровне нашей модели мы предполагаем, что обработка выполняется корректно, и ее результат приходит в узел Тсум. Вам предлагается раз- работать более детальную модель этой обработки в упражнении 2. После того как вы разработаете модель потока транзакций для обработки, вы, надеюсь, согласитесь со мной, что в данном случае уместнее было бы использовать модель потока данных, или модель потока управления. Выбранный мной способ разбиения на части дан- ной модели был удобен для меня, и он в точности повторяет структуру форм, пред- ложенную ВНС. У вас может быть свое собственное мнение на этот счет, и оно при- ведет к другому, но не менее эффективному разбиению проблемы на части. 6.4.4. Выбор путей и/или порожденных подграфов тестирования Следует рассмотреть несколько ситуаций, зависящих от того, есть ли в иссле- дуемой модели узлы порождения/расщепления и/или слияния/поглощения. В любом случае мы предполагаем, что у нас нет циклов или что циклы могут
присутствовать во вспомогательных моделях. Поскольку модели потоков тран- закций, как правило, состоят из множества маленьких независимых субмоделей, то, скорее всего, даже если вы решите использовать модель потока транзакций, может оказаться, что некоторые из субмоделей лучше описываются при помощи модели потока данных или модели потока управления. Ниже приведены некото- рые наиболее часто встречающиеся случаи: 1. Чистая модель потока управления, есть только ветвления и соединения. 2. Узлы слияния и поглощения, нет ветвлений, нет соединений. 3. Узлы слияния и поглощения с ветвлениями и соединениями. 4. Управляющие потоки с расщеплениями и порождениями, но без слияний и поглощений. 5. Общий случай. Случай 1: Чистая модель потока управления Этот случай полностью идентичен случаю тестирования потока управления. Если все потоки транзакций подобны потокам управления, то лучше выбрать модель потоков управления. По сравнению с моделями потоков управления модели по- токов транзакций имеют три отличия. 1. Обычно приходится рассматривать много потоков транзакций, несмотря на то, что все они относительно простые. 2. Большая вероятность существования моделей с числом входов и выхо- дов, отличным от единицы. Транзакции могут приходить из разных источ- ников и вследствие этого помещаться в различные очереди на обработку. Транзакции могут направляться в различные точки назначения и вследс- твие этого помещаться в различные выходные очереди. Нам недостаточно убедиться в корректности обработки транзакций, необходимо также прове- рить, что транзакции прошли правильным маршрутом. В принципе вас не должно удовлетворять простое покрытие связей, вы должны обеспечить та- кое покрытие для всех имеющих смысл комбинаций «вход - выход». 3. Кроме того, вам еще надо рассмотреть и проверить правила упорядочения в очередях. Случай 2: Узлы слияния и поглощения, нет ветвления, нет соединения Как обсуждалось в главе 5, разделе 5.4.4, это случай чистой модели потока дан- ных. Вы можете создать порожденный подграф для каждого возможного выхо- да. Вы начинаете его строить из выходного узла и идете в обратном направлении к стартовым узлу(ам) для данного выхода. Включите все обратные ветвления, по- скольку все они вносят свой вклад в обработку данных. В нашем примере, строя порожденный подграф, идущий назад из СЮ, мы придем в Сба. Затем мы должны включить в него связь из узла С1 (и все, что в него входит) и связь из Pal, поскольку обе связи поставляют в Сба данные, необходимые для обработки.
Случай 3: Узлы слияния и поглощения с ветвлением и соединением В этом случае порождения и расщепления отсутствуют. Несколько транзакций входят в модель, и меньшее их число выходит. Остальные транзакции поглощают- ся в процессе прохождения модели. Этот случай идентичен случаю 3 раздела 5.4.4 главы 5. Если вы прочли эту главу, то вам надо прочесть то, что относится к данно- му случаю еще раз, и интерпретировать его на языке потоков транзакций. Если вы не читали про этот случай, то прочитайте, игнорируя все, что касается узлов вы- бора. Убедитесь, что вы, по крайней мере, охватили достаточное количество путей, чтобы обеспечить покрытие связей. Вы создаете порожденный подграф так же, как в предыдущем случае, за исклю- чением того, что после узлов соединения вы должны следовать по обеим входя- щим в этот узел соединения связям, чтобы убедиться, что вы включили в порож- денный подграф все источники данных. Этет порожденный подграф определяет набор тестовых вариантов. Рассмотрим существующие в модели узлы ветвления. Каждое значение пара- метра, управляющего ветвлением, определяет выбор одного из альтернативных путей. Выберите один из них. Теперь некоторые входные транзакции уже не нуж- ны, следовательно, их можно убрать. Продолжайте этот процесс до тех пор, пока у вас не останется только один определенный путь (и соответствующие входные транзакции). Проделайте это еще раз, выбрав другую ветвь для другого варианта тестового варианта. Перебор следует продолжать до тех пор, пока вы не обеспечи- те покрытия связей. Случай 4: Управляющие потоки с расщеплениями и порождениями, но без слияний и поглощений Это достаточно простой случай. Начните с выхода и сделайте порожденный под- граф для каждой транзакции, приходящей в выходные узлы. Сделайте один по- рожденный подграф (от выхода до всех стартовых узлов, имеющих к нему отно- шение) для каждой выходной транзакции. Поделите этот порожденный подграф на более мелкие части (больше тестовых вариантов), чтобы обеспечить покрытие связей для узлов ветвления. Случай 5: Общий случай В данном случае не существует простых рецептов. Общая идея состоит в том, что- бы сделать порожденный подграф для каждой выходной транзакции. Включите в него все входные транзакции, обеспечивающие данные. Если в каком-либо из этих порожденных подграфов существуют управляющие потоки, убедитесь, что вы разделили их и получили дополнительные тестовые варианты, гарантирую- щие покрытие связей в каждом из порожденных подграфов. Может показаться, что мы создаем избыточные тестовые варианты, поскольку порожденные подгра- фы перекрываются, — и, обеспечив покрытие связей для транзакции типа А, мы можем проделать это заново для транзакции типа В (в другом порожденном под- графе, включающем в себя некоторые ветви из предыдущего порожденного под- графа). Для мотивировки этого, казалось бы, избыточного действия достаточно
задать себе вопрос: «Что является целью тестирования»?» Я уже ранее говорил, что системное тестирование — это не проверка работы отдельных узлов, а провер- ка того, правильно ли транзакции проходят от обработки к обработке. Поскольку ббльшая часть обработки (в случае потоков транзакций) включает в себя услов- ные ветви, которые частично зависят от типа транзакций, то не лишним будет про- верить одну и ту же логику для различных типов транзакций. По сути, такое «из- быточное» покрытие связей может оказаться единственным способом проверить глубоко скрытые составные предикаты. Используя данные выше рекомендации, мы получаем два семейства тестов. С10/С6а/ра1. С6а/С1/Ф1а/Ф1 С10/С6а/ра1. С6а/С1/Т1/Ф1д/Ф1а/Ф1. Т1/Тсум/..С11а...0т1/Фр1/Ам1 Это два семейства тестов, поскольку для транспортных средств возникает мно- го тестов. И поэтому мы должны проверить вопросы синхронизации и поведение очереди. 6.4.5. Тестирование синхронизации При слиянии двух или более транзакций или если одна поглощает другую, мы всегда должны спроектировать и провести тестирование синхронизации. В нашей модели мы можем рассмотреть в качестве примера узел Сба или узел Т1. Оба они являются узлами поглощения. Узел Сба незамысловат, и для его проверки нам необходимо пять тестов. Узел Т1 представляется более, интересным и перспек- тивным, поскольку в нем происходит слияние формы (льготы на транспортное средство), которая порождена в этой же модели. Посмотрев на эту модель, вы мо- жете ошибочно заявить: «Мне не нужно пяти тестовых вариантов. Путь от Ф1д к Т1, очевидно, короче, чем путь, лежащий через процедуру обработки транспортно- го средства (от Cl 1а до Тсум). Таким образом, я могу сделать вывод, что транзак- ция формы 2106 всегда приходит в узел Т1 раньше, чем данные о транспортном средстве, и ждет их там. Значит, у нас есть только 2 варианта для рассмотрения. Либо форма 2106 приходит раньше данных о транспортном средстве, либо данные о транспортном средстве отсутствуют». Если вы и в самом деле так считаете, то делаете ошибочное допущение и попа- дете в ту же ловушку, что и программисты, создавшие программу, которую вы тес- тируете. Это всё рациональные приближения, однако природа ошибок не рацио- нальна. К тому же обе связи, входящие в Т1, могли бы представлять собой очереди (в данном примере это не так), и правило упорядочения может вызывать любые перестановки. Если вы не можете с уверенностью сказать, что возможен лишь один опреде- ленный порядок (например, форма 2106 приходит раньше данных о транспортном средстве), то вам будет лучше проверить все случаи. Система должна вести себя разумно для всех случаев. Я подразумеваю, что она не уничтожает, не изменяет и не теряет данные, а неполные транзакции она отвергает, уведомляя об этом поль- зователя или иную систему, породившую транзакцию. Насколько глубоко мы должны проверять синхронизацию? Должны ли мы учитывать взаимодействие одного узла слияния с другим, находящимся ниже
в исследуемом порожденном подграфе? Гипотетически — да, но на самом деле не стоит этого делать. Число тестов растет экспоненциально] а продуктивность таких тестов синхронизации высокого порядка совсем не очевидна. Более того, проведе- ние тестов для одного слияния уже является непростой задачей, проверка же по- следовательности слияний может оказаться невозможной. А что, если один и тот же узел слияния встречается в нескольких порожденных подграфах? Следует ли повторять тесты синхронизации в каждом из них? Скорее всего, не следует, и главным образом потому, что это приведет к быстрому росту числа тестовых вариантов. Но есть и другая причина. Вы, возможно, сможете про- верить эти случаи быстрее и с меньшими усилиями путем автоматической генера- ции соответствующим образом подобранных случайных тестовых вариантов. 6.4.6. Тестирование очереди Проверка любой, не слишком простой очереди требует применения целой груп- пы тестов. Где это следует делать, в системном тестировании или на более низком уровне компонентного тестирования? Если узел имеет только одну входящую связь, и у меня есть причины считать, что этой очередью управляет представля- емый этим узлом компонент, то я отдаю предпочтение тестированию очереди в контексте компонентного тестирования. Если узел является узлом слияния, по- глощения или соединения (несколько входящих связей), то я буду должен прове- рить очередь на уровне компонентов, а затем повторить эти тесты при тестирова- нии системы. Какие именно тесты вам нужны, зависит от правила упорядочения и правила выбора сервера, если он есть. Ниже приводятся некоторые полезные виды тестов. 1. Тестирование пределов длины очереди. * Максимальная длина очереди. Попытайтесь превысить предельно до- пустимое число элементов в очереди. • Пустая очередь. Активизируйте обработку, когда в очереди ничего нет. • Проверка циклов. Узел, обрабатывающий очередь, содержит цикл для обработки элементов очереди (особенно это касается групповых серве- ров). Используйте методы тестирования циклов для нескольких элемен- тов в очереди. • Динамические изменения длины очереди. Попытка добавить транзак- цию в очередь (особенно в очередь пакетной обработки) во время прове- дения обработки элементов является, очевидно, необходимым тестовым вариантом. Кроме этого, попробуйте удалить элемент из очереди, пока обработчик очереди активен, если система обработки это вам позволит. 2. Тестирование сортировки и выбора. Часто правила упорядочения включа- ют в себя процедуру сортировки. Например, правило может указывать, что в первую очередь обрабатываются наиболее старые транзакции. Это правило отличается от правила построения очереди FIFO (First in First Out — первым прибыл, первым обслужен). Очередь FIFO строится на основе положения
элемента в очереди. За основу в правиле «старейшая транзакция обрабаты- вается первой» берется отметка времени в контрольной записи транзакции. Поскольку транзакции проходят различные пути до того, как становятся в данную очередь, порядок FIFO может отличаться от порядка отметок вре- мени. Другой пример — это очереди с приоритетом, в которых существует внутренняя сортировка по степени приоритета. Обработка должна включать в себя явную процедуру сортировки или, если очередь не слишком длинная, может осуществляться сканирование всей очереди, чтобы выбрать следую- щий элемент для обработки. Оба этих варианта представляют собой неяв- ную процедуру сортировки. Сортировка всегда происходит на основе реаль- ного или скрытого ключа. Существуют элегантные способы тестирования процедур сортировки, но они лежат за рамками данной книги. Мы ограни- чимся некоторыми простыми, но эффективными эвристическими методами. Ниже приведено несколько случаев, которые стоит проверить. • Правильное упорядочение. « Все элементы имеют одинаковые ключи сортировки. « Элементы располагаются в обратном порядке. « Присутствует только один элемент в очереди. Проверьте все дискретные ключи сортировки (то есть приоритеты). « Один элемент для каждого дискретного ключа сортировки. • Для многоуровневых ключей (например, возраст внутри одного приори- тета) рассмотрите комбинации приведенных выше тестов в контексте тестирования вложенных циклов. 3. Тестирование упорядочения очереди. Если в вашем случае правило упоря- дочения отличается от FIFO, вы должны провести тестирование упорядо- чения очереди, чтобы убедиться, что оно было реализовано корректно. Если это правило определяется неявной сортировкой (например, приоритетом), то используйте описанные выше тесты. За исключением этого, дать общие рекомендации довольно трудно, поскольку правила упорядочения могут быть самыми разными. 4. Тестирование приоритетов. Следует различать многоуровневые приорите- ты в одной очереди и отдельную очередь для каждого приоритета. В первом случае тестирование представляет собой проверку сортировки, основанной на приоритетах. Во втором случае необходимы некоторые дополнительные тесты; • Существует только один приоритет. Рассмотреть этот случай для каждо- го приоритета. • Присутствуют все приоритеты, берется по одному элементу на каждый приоритет. « Присутствуют все приоритеты, берется несколько элементов на каждый приоритет.
* Приоритеты меняются во время обработки (если это позволяет прило- жение). Протестируйте случаи повышения и понижения приоритета. Очереди по приоритету заслуживают особого внимания, особенно если суще- ствуют другие ключи, используемые в других процессах. Например, пусть в одной очереди ключ определяется в области значений, а в другой очереди ключ пред- ставляет собой степень секретности. Для ключевых значений сначала обрабаты- ваются транзакции, соответствующие наибольшим значениям, затем меньшим, и так далее. В очереди, упорядоченной по степени безопасности, первыми обрабаты- ваются совершенно секретные транзакции, затем просто секретные, затем довери- тельные и так далее. Обе очереди являются очередями по приоритету, поскольку, хотя одно поле и называется «значение», а другое «степень секретности», поведе- ние элементов в обеих очередях определяется приоритетом. О чем тогда беспоко- иться? Все дело в том, что при возникновении подобной ситуации программист с большой вероятностью перепутает две очереди и использует неверный ключ. В моей практике я видел, как «конфиденциальность» путали с «безопасностью» и оба эти понятия путали с «приоритетом». 5. Тестирование правила выбора сервера. Проверяйте множественные серве- ры с одной очередью путем низкоуровневого компонентного тестирования. Если у вас есть несколько очередей, которые служат входными связями во множественный сервер, то правило выбора сервера должно быть провере- но (или хотя бы перепроверено) при тестировании системы. Тестирование правила выбора сервера напоминает тестирование сортировки, и выпол- нять его надо очень тщательно при помощи следующих вариантов: • Все элементы в одной очереди. * Во всех очередях один элемент. • Во всех очередях одинаковое число элементов. 6.4.7. Активизация Проблема активизации при тестировании потоков транзакций отличается от ана- логичной проблемы в методах тестирования потоков управления или потоков дан- ных. Задача заключается не в том, чтобы найти такие транзакции, которые просле- дуют по выбранному пути. На самом деле суть проблемы — создать транзакции, выполняющие это условие, и ввести эти транзакции в систему. Хотя обычные транзакции, как правило, не слишком сложны, тины транзакций, представленные в разделе 6.4.1, иногда бывает просто невозможно ввести. Ниже приведены неко- торые характерные проблемы и возможные способы их решения. 1. Ошибки, отрицательное квитирование и восстанавливающие транзакции из других систем. Это было моим проклятием Вы не можете получить эти тран- закции, не заставив другую систему вести себя неправильно. Вам необходи- ма транзакция из другой системы, информирующая вас, что один из ваших блоков данных был утерян или искажен. Однако вы не можете послать ей блок данных или искаженный блок, поскольку такие ошибки могут быть об-
наружены промежуточными системами. Вам придется заставить другую сис- тему послать вам сообщение об ошибке, хотя на самом деле ошибки не было. Вы пытаетесь наладить сотрудничество, но в ответ вам с пафосом заявляют: «Наша система никогда не посылает сообщения об ошибках!» Вы пытаетесь как-то решить эту проблему, а заканчивается все тем, что вы объясняете раз- гневанному чиновнику в полосатом костюме из государственного департа- мента в Вашингтоне, что не собирались раздуть международный скандал1. На этот случай я не знаю приемлемого технического решения, поскольку это не техническая проблема. В крайнем случае вам придется построить имитаторы всех таких недружественных интерфейсов и протестировать все случаи, ис- пользуя эти имитаторы. А потом остается только надеяться на лучшее. 2. Внутренние транзакции, связанные с восстановлением системы и нелогич- ными условиями. Система должна иметь защиту от аварий, таких как от- казы программного или аппаратного обеспечения. Вы не сможете протес- тировать защитные механизмы, не создав в точности такую же ситуацию, против которой система должна себя защищать. Следует точно узнать, при- нимаются ли необходимые меры по защите. Вы должны сломать доктрину безопасности. Проверить, предусмотрено ли в вашем случае аварийное вос- становление состояния системы и данных. Вы должны имитировать все ме- ханизмы аварий и порождаемые ими транзакции. 3. Внутренние транзакции для восстановления данных и нелогичных усло- вий. Если система обнаруживает потерянные или дублированные транзак- ции, то и тестировщик должен иметь возможность терять или дублировать транзакции. Любой механизм восстановления данных рассчитан на опре- деленный сценарий их потери или искажения. Вы должны воспроизвести каждый такой сценарий для соответствующих транзакций. На практике задача активизации заключается в том, чтобы правильно генериро- вать и внедрить необходимые вам для проверки системы транзакции. Единственный разумный способ это сделать — это встроить в систему генератор транзакций на ран- ней стадии проектирования. Минимум действий, которые должен уметь выполнять встроенный генератор транзакций, выглядит следующим образом. 1. Создание любых заданных транзакций, как корректных, так и некорректных. 2. Размещение эти транзакций в любом месте заданной очереди. 3. Удаление выбранных транзакций из очереди. 6.4.8. Предсказание итогов Нашей задачей при проведении тестирования не является детальная проверка данных в транзакциях. Цель системного тестирования (в контексте модели потока транзакций) заключается в проверке корректного прохождения транзакций, в том числе их порождения, завершения и так далее. Ожидаемым итогом в этом случае 1 Это реальный факт из моей практики.
является определение того, какие транзакции в каких очередях должны находить- ся до и после тестирования — предсказание конечного состояния транзакции при заданном начальном состоянии. На практике, однако, перед тестировщиком стоит задача не предсказать итог, а проверить его. Вы должны сравнить все включенные в процесс очереди до и по- сле проведения теста. По меньшей мере вам необходимо иметь возможность, про- ведя тестирование, заморозить систему, или, как альтернативный вариант, уметь делать моментальную запись всех интересующих вас очередей. Здесь подразуме- вается использование инструментов тестирования, и лучше всего, если они будут встроены в проект. 6.4.9. Проверка соответствия пути На самом деле если существуют слияния или порождения, то это будет провер- кой соответствия порожденного подграфа. Проблема заключается не в том, чтобы убедиться в правильности пути, а в том, чтобы найти способ встроить в систему инструменты, которые это будут делать. Существует два основных источника не- обходимых данных, и в обоих случаях вам, возможно, придется создавать доста- точно продуманную программу, поскольку вероятность того, что в универсальных инструментах предусмотрены все возможности ваших транзакций, весьма мала. 1. Существующие записи. Системы обработки транзакций обычно включают в себя запись активности транзакций, которая требуется в различных при- ложениях. Например, информацию о счетах, журнал безопасности, резерв- ные и архивные данные. Эти данные записываются в узлах, которые чаще всего и являются целью тестировщика. Например, в системах восстанов- ления данных обычной практикой является запись состава всех активных очередей. Прежде чем вы потребуете расширить возможности регистрации данных в системе, исследуйте все журналы регистрации и записи, необхо- димые в приложении, и подумайте, могут ли эти данные помочь вам прове- рить исследуемый путь. 2. Встроенная регистрация. Обсуждаемое в предыдущем пункте дополнение данных, предоставляемых приложением, необходимо для устранения бе- лых пятен. Постарайтесь ограничиться минимальными добавлениями, что- бы дополнительная регистрация данных не влияла существенно на поведе- ние системы. Как правило, это вполне реально осуществить, и часто объем ресурсов, достаточный для проведения самой полной регистрации транзак- ций не превышает нескольких процентов от общего объема доступных ре- сурсов. Как правило, такие возможности регистрации должны встраиваться сразу, поскольку сделать это задним числом будет очень сложно. 3. Действия в режиме трассировки. Это наиболее приятный способ регистра- ции. Транзакции вполне могут запускаться в режиме трассировки. Это озна- чает, что производится постоянная запись всех процессов, в которых участ- вовали эти транзакции, и всех очередей, в которых они стояли. Разумеется, такая возможность тоже должна быть встроена в систему. Вне зависимости
от того, насколько важен режим трассировки для тестировщика, он вполне оправданно считается отличным инструментом для отладки системы. 6.5. Рассмотрение приложений 6.5.1. Индикаторы приложений Насколько хорошо вы сможете описать поведение системы при таком моделиро- вании? Критериями применимости данного метода могут служить положитель- ные ответы на приведенные ниже вопросы. 1. Выполняется ли работа дискретными единицами? 2. Распределяются ли единицы работы между обрабатывающими модулями при помощи очередей или подобных интерфейсов? 3. Существуют ли в вашем случае множественные серверы? 4. Выполняются ли ваши процессы квазипараллельно? 5. Существует ли между процессами связь в виде сообщений? 6.5.2. Предположения об ошибках Основное предположение должно быть следующим — каждый отдельный процесс работает корректно (был проверен со всех сторон на более ранней стадии инте- грации), а ошибки, которые мы ищем, возникают вследствие некорректной реа- лизации связи между компонентами или как побочный эффект многозадачности. Типичный список предположений об ошибках включает в себя несколько стан- дартных пунктов. 1. Некорректные очереди. Пропуск очередей, лишние очереди, неправильные типы очередей. 2. Некорректные порождения или расщепления. Система использует порож- дения транзакций неправильного типа, неверный порождающий элемент, создание копий. 3. Некорректные слияния или поглощения. Неправильные слияния или по- глощения, потери. 4. Ошибки маршрутизации очереди. Соединение выходов с неверными вход- ными очередями. 5. Ошибки в правилах упорядочения. Действует неверное правило упорядо- чения. 6.5.3. Ограничения и предостережения Мы предполагаем, что наш проект обладает правильным дизайном. Он имеет ие- рархическую структуру, в нем существует ясное разделение между обработкой
данных и управлением очередями, транзакции однозначно делятся на типы, осу- ществляется явная запись управления транзакциями, и маршрутизация транзак- ций производится централизованно. Чем лучше проект, тем легче будет обеспечить полное покрытие при помощи тестирования потоков транзакций. Это означа- ет, что тестировщик сможет сделать обоснованные предсказания (проведя соот- ветствующие тесты) о пригодности программы к использованию. Предположим теперь, что у вас плохой проект. Значит ли это, что тестирование потоков транз- акций будет бесполезно? Нет, оно все равно будет очень полезно. Обсуждаемые здесь тесты легко сломают программу, основанную на плохом проектировании. Единственное, что вы не сможете сделать для плохого проекта, — это статистичес- ки оправданно предсказать его пригодность к использованию. Единственное важное ограничение для этой модели — это требование марков- ского поведения от каждого узла. В случае немарковского поведения у вас не бу- дет другого выбора, кроме как тестировать каждый возможный путь для каждой возможной транзакции, поскольку поведение будет зависеть не только от данных, содержащихся в транзакции, но и от предыстории ее поведения. Такое тестирова- ние редко осуществимо на практике. Сколько-нибудь разумное понятие покры- тия бесполезно при отсутствии марковского поведения. Если у вас случай именно такого поведения и вы выполните предложенные здесь тесты, то ничего не добье- тесь, кроме ошибочной уверенности. Немарковское поведение может быть сколь угодно сложным, поэтому любое выполняемое вами покрытие охватит лишь не- большую часть возможных вариантов. Что вам следует делать при встрече с не- марковским поведением? 1. Избавиться от него путем перепроектирования. В любом случае это лучший выбор. В большинстве случаев можно обойтись без немарковского поведе- ния. Оно возникает, когда люди недостаточно хорошо разобрались в вопро- се. 2. Изолировать его. Вам, возможно, придется это сделать, если ваша модель описывает поведение человека или поведение других, не контролируемых вами систем. Процедура изоляции может заключаться в наложении ограни- чений на действия (изменение спецификации) или выделении подобного поведения в отдельную субмодель, которую вам придется проверить очень тщательно, прежде чем вы перейдете к тестированию системы более высо- кого уровня. 3. Смириться с риском. Иногда это допустимо. То, что приемлемо в развле- кательных программах, не может быть приемлемо в жизненно важном про- граммном обеспечении. 6.5.4. Автоматизация и инструментальные средства Рассмотрим отдельно автоматизацию выполнения тестов и автоматизацию их проектирования. 1. Автоматизация выполнения тестов. Необходимость автоматизации вы- полнения частично была рассмотрена выше в разделах 6.4.7-6.4.Э. Что ка-
сается коммерчески доступных инструментов тестирования, то системы покрытия/воспроизведения и языки подготовки сценариев являются на- иболее подходящими инструментами для автоматизации выполнения тес- тов. Однако в большинстве систем разработки, о которых стоило бы гово- рить, наличие встроенных средств тестирования — обязательное условие. 2. Автоматизация разработки тестов. Системы автоматизации могут варьиро- ваться от тривиальных до сложнейших. Языки и системы, предназначенные для создания генераторов тестов, широко распространены (как коммерче- ские, так и частные). Имеет смысл потратить пять лет работы, чтобы создать специализированный генератор автоматического тестирования транзакций для проекта, разработка которого потребует 100 лет общих трудозатрат. Хотя здесь редко встречаются непреодолимые технические трудности, я до- пускаю, что может быть достаточно трудно убедить нужных людей, что инс- трументы тестирования подобного рода стоят потраченных на них времени и сил. 6.6. Резюме Модель потока транзакций является эффективной моделью, применяемой в высокоуровневом системном тестировании большого количества систем. Моделирование начинается с идентификации интересующих нас транзакций, осо- бенно мест, где они порождаются и завершаются и обстоятельств, при которых это происходит. Модель основана на допущении о марковском процессе1. В ней так же предполагается, что подробные модели обработки были созданы и использова- лись на более низком уровне компонентного тестирования, на стадии, предшест- вующей интеграции. Основное внимание при тестировании потоков транзакций уделяется очередям, и маршрутам транзакций в системе. Мы рассмотрели эври- стическую иерархию покрытия, основанную на порожденном подграфе. 6.7. Вопросы для самопроверки 1. Дайте определение (в контексте тестирования потоков транзакций) следу- ющих терминов: узел поглощения, обслуживание пакета, покрытие порож- дения/завершения, стартовый узел, ограниченная очередь, узел ветвления, предикат ветвления, управляющая входящая связь, дочерняя транзакция, узел завершения, FCFS, FIFO, узел соединения, LCFS, LIFO, покрытие связей, маркировка, марковский узел, марковский потоковый граф, узел слияния, материнская транзакция, множественный сервер, очередь, покры- тие узлов, покрытие зарождения/выхода, узел зарождения, родительская 1 Иными словами полагают, что поток транзакций является марковским процессом (процессом без последействия), в котором будущее поведение транзакции зависит только от текущего состояния и не зависит от предыстории процесса. — Примеч. научи, ред.
транзакция, транзакция - хищник, транзакция - жертва, очередь по при- оритету, тестирование приоритетов, правило упорядочения, тестирование правила упорядочения, тесты очереди, случайное обслуживание, правило выбора сервера, односерверная очередь, порожденный подграф, тестирова- ние сортировки, узел расщепления, тесты синхронизации, задача, действия в режиме трассировки, транзакция, узел ветвления транзакции, предикат ветвления транзакции, управляющая запись транзакции, узел соединения транзакций, регистрация транзакций, тестирование выбора транзакции, со- стояние транзакции, маркер транзакции, тип транзакции. 2. Разработайте подробную модель части формы 2106, связанной с расхода- ми на транспортные средства. Считайте, что число транспортных средств ограничено п. Вводя соответствующие данные для каждого транспортного средства (0т1, Фр1, Ам1, 011а) имейте в виду, что вы можете вводить фактичес- кие расходы и амортизацию, только если вы являетесь владельцем транс- портного средства; однако вы не обязаны декларировать фактические рас- ходы. Если же вы это делаете, то не обязаны декларировать амортизацию. Считайте, что вы нашли способ получить максимальные льготы (выбрав между стандартными и фактическими льготами). Введите в эту субмодель данные для всех транспортных средств и получите одно число общих льгот на транспортные средства (Тсум). Разработайте модель, выберите пути, акти- визируйте их, определите, что вы хотите проверить, исследуйте синхрони- зацию для слияния транзакций, и так далее. Проводите только чистые тес- ты. 3. Разработайте грязные тесты для задачи 2. Рассмотрите потерю, дублирова- ние, искажение данных о транспортном средстве. Учтите, что вы не можете декларировать фактические расходы для одного транспортного средства, а амортизацию для другого. Все данные о транспортном средстве (От 1, Фр1, Ам 1) должны являться частью соответствующего набора для данного транспорт- ного средства. 4. Для проверки слияния двух транзакций необходимо пять контрольных тес- тов, в случае трех транзакций таких тестов должно быть уже 25. Сколько тестовых вариантов потребует проверка слияния четырех транзакций? А сколько потребует слияние п транзакций? 5. Разработайте модель потока транзакций для формы 1040: (а) строки 7-22, (б) строки 23-30, (в) строки 32-40, (г) строки 41-45, (д) строки 47-53, (е) строки 45-60. В каждом случае считайте, что все входные значения вво- дятся в виде единой транзакции, возможно, из предыдущего блока строк. Моделируйте эти вычисления как единый элемент обработки, который не надо тестировать. Рассматривайте каждую встречающуюся форму или бланк как транзакции, которые могут порождаться и/или поглощаться как положено. Включите в модель логику для определения того, нужны или не нужны в ней данные формы. Например, в строке 14 в случае существования «дополнительных доходов» будет создана форма 4797, которая потом будет возвращена заполненной соответствующим образом и поглощена формой
1040, то же самое будет с W2, бланком В, бланком С, формой 3903 и так да- лее. Не пытайтесь моделировать эти формы. Создавайте пустые формы, как того требует логика, отправляйте их на соответствующий узел обработки форм, затем принимайте данные формы обратно в соответствующие строки формы 1040. Разработайте следующие типы тестов: покрытие узлов, покры- тие связей, покрытие порождения/завершения. 6. Выполните задачу 5 в предположении, что вспомогательные формы могут быть сначала открыты, а затем оставлены незаполненными, поскольку ока- залось, что в них нет необходимости. 7. Выполните еще раз задачу 5 в предположении, что различные строки могут заполняться в произвольном порядке при условии, что существуют требу- емые данные (то есть вы не можете добавлять числа, пока они не введены). Разработайте необходимые тесты синхронизации, считая, что входящие формы поступают по очереди, но в произвольном порядке.
Тестирование доменов 7.1. Обзор Тестирование доменов используется для проверки такого программного обеспе- чения или его частей, в которых преобладают численные вычисления. Оно явля- ется альтернативой общему эвристическому методу тестирования экстремальных значений и предельных значений входных величин. 7.2. Основные термины Внешние термины: алгебра, неоднозначный, приложение, аппроксимировать, мас- сив, вычислять, оператор CASE, классификация, код, коэффициент, коллинеарный, константа, несовместимый, координатные оси, компланарный, проверка соответ- ствия данных, размерность, уравнение, эквидистантный, выражение, ЛОЖЬ, функция, иерархия, IF-THEN-ELSE, реализация, неравенство, пересекаться линия, линейный, логика, сопровождение, означать, модель, нелинейный, численный, пе- рекрывать, параллельный, плоскость, точка, полиномиальный, точность, обработ- ка, программа, программист, радиус, область, округление, набор, программное обес- печение, пространство, подмножество, поверхность, символическая подстановка, система, таблица, управляемый таблицами, тестируемость, преобразование, дерево, Внутренние термины: слепота, ошибка, случайная корректность, поток управ- ления, поток данных, граф, ввод, связь, покрытие связей, вес связи, объект, итог, узел, покрытие узлов, вес узла, вывод, предикат, отношение, спецификация, тест, тестовый вариант, поток транзакций. Входная переменная. Численный объект, который система получает для обработ- ки при тестировании. В общем случае система обрабатывает п входных переменных.
Входной вектор. Набор значений п входных переменных, включающий одно значение для каждой переменной. В наших задачах мы будем рассматривать вход- ной вектор так, как если бы он являлся массивом. Так же мы будем использовать эквивалентные термины: контрольный вектор, контрольная точка. Входное пространство. Абстрактное n-мерное пространство, в котором опре- деляется входной вектор. Наличие входных переменных подразумевает наличие п-мерного входного пространства. Выходная переменная. В тестировании доменов означает численную перемен- ную в тестируемой системе. В общем случае система вычисляет значения m вы- ходных переменных. Выходной вектор. Набор значений m выходных переменных. Как и для случая входного вектора, мы будем рассматривать выходной вектор так, как если бы он являлся массивом. Выходное пространство, m-мерное пространство выходных векторов. Домен. Подпространство входного пространства, в котором задается обработ- ка, выполняемая тестируемой системой. Мы считаем, что известен способ, с по- мощью которого можно определить, принадлежит ли входной вектор данному домену или нет. При тестировании доменов, они задаются системой граничных неравенств (см. ниже). Область. Подпространство выходного пространства, состоящее из значений, вычисленных тестируемой системой (выходных значений). Каждому домену со- ответствует своя область. Граница домена. Способ определения домена. Обычно определение происходит в форме алгебраических неравенств. Мы будем использовать термин «граница» вместо термина «граница домена» там, где не может возникнуть неоднозначности. Граничное неравенство. Алгебраическое выражение, содержащее входные пе- ременные, с помощью которого можно определить, какие точки входного про- странства принадлежат рассматриваемому домену. К примеру, неравенство х >= 7 означает, что для всех точек, содержащихся в данном домене, значение входной переменной х будет больше или равно семи. Х<7 Х = 7 Х>7 Граничное уравнение. Уравнение, получающееся при превращении граничного неравенства в равенство (то есть при замене символа «>=» на «=»). Граничное множество домена. Система неравенств, совместно определяющих домен: напрцмер, х>=7, х<44 определяют домен, как диапазон чисел, лежащий меж- ду 7 и 44, причем 7 в него включается, а 44 — нет. Поскольку домены задаются со- ответствующими системами уравнений, мы в дальнейшем будем подразумевать под этими системами уравнений сами домены. X = 7 X >= 7 & X <44 X = 44 Рассматриваемый домен
Закрытые границы. Граница домена называется закрытой, если точки, лежа- щие на ней, включаются в рассматриваемый домен. Например, в домене х >= 7 граница закрыта, поскольку значение 7 включено в данный домен. В одномерном пространстве закрытые границы изображаются черными точками. Открытые границы. Если граница не закрыта, то она открыта. В этом случае точки на границе не принадлежат рассматриваемому домену, они принадлежат смежному домену, если таковой существует. В предыдущем примере домен закрыт в точке х = 7 и открыт в точке х = 44, поскольку точка 44 не принадлежит этому домену. В одномерном пространстве, закрытые границы изображаются заштрихо- ванными точками. Закрытый домен. Домен, у которого все границы закрыты. Открытый домен. Домен, у которого все границы открыты. Домен не обя- зательно должен быть открытым или закрытым. Так, например, вполне может существовать домен с одной открытой и одной закрытой границами. На ри- сунке рассматриваемый домен ограничен пятью неравенствами: X > О, X <= 12, 2Y <= Х+4, 2Y >= X- 8, и Y > 0. В пространстве с размерностью 2 штриховка отме- чает сторону, с которой домен закрыт. В предыдущем примере оси X (Y = 0) и Y(X = 0) не включены в рассматриваемый домен, а линия Х<2 и две диагональ- ные границы — включены. Гиперплоскость. В n-мерном пространстве линейная поверхность с размер- ностью меньшей, чем п называется гиперплоскостью. Например, на двумерной плоскости линия и точка являются гиперплоскостями, в одномерном простран- стве точка является гиперплоскостью, в трехмерном пространстве плоскость, линия и точка — гиперплоскости. Границы доменов представляют собой гипер- плоскости, как правило (но не всегда), с размерностью п-1. Узловая точка. Точка пересечения двух или более границ доменов. В литера- туре ее часто называют «особая точка». В n-мерном пространстве узловую точку можно получить, решая систему из п (линейно независимых) граничных урав- нений.
Внутренняя точка. Точка, лежащая внутри рассматриваемого домена. Внешняя точка. Точка, лежащая вне рассматриваемого домена. Вырожденный домен. В n-мерном пространстве дсмеп с размерностью мень- шей, чем п. Так, например, в двухмерном пространстве вырожденный домен со- стоит из линии или точки. В трехмерном пространстве вырожденный домен со- стоит из плоскости, линии или точки. Вырожденная граница. В n-мерном пространстве граница с размерностью мень- шей, чем п-1. Так, например, в трехмерном пространстве вырожденная граница домена может включать в себя линию или точку, но не плоскость. В двухмерном пространстве вырожденная граница домена состоит из точки, но не из линии. Смежные домены. Два домена называются смежными, если у них общее гранич- ное неравенство. Если граница рассматриваемого домена закрыта, то эта же гра- ница смежного домена должна быть открыта, и наоборот. 11а рисунке рассматрива- емый домен закрыт по отношению к своей верхней диагональной границе, поэтому, смежный домен над линией открыт по отношению к данной границе. Эпсилон-окрестность (точки). Маленькая область вокруг точки радиуса е (эп- силон), где £ — произвольная, но маленькая величина. На практике мы выбираем
щего для нас интерес в приложении. Иными словами, наибольшее значение е вы- бирается из условия, чтобы ошибка порядка £ или меньше была приемлемой для данного приложения. Точка НА. Точка, лежащая на границе домена или находящаяся так близко к границе, насколько это возможно, чтобы удовлетворять условиям, относящим- ся к границе1. Точка ВНЕ [СОНЕ78] Если домен открыт по отношению к какой-либо грани- це, то точка ВНЕ этой границы — внутренняя точка, лежащая в непосредственной близости от границы (в пределах е-окрестности). Если домен закрыт, тогда точ- ка ВНЕ является внешней точкой и лежит в непосредственной близости от гра- ницы снаружи. Это означает, что точка ВНЕ не удовлетворяет условиям, относя- щимся к границе [JENG 94]. Очевидно, у двух смежных доменов может быть одна и та же точка ВНЕ. Запомнить определение вам поможет следующий акроним: ЗВСОВИ — Закрыт ВНЕ Снаружи, Открыт ВНЕ Изнутри1 2. Линейное неравенство. Неравенство вида е1х1 + а2х2 + а3х3 +...+апхп+...+ к >= 0, где хп — элементы входного вектора (то есть входные переменные), а, — численные коэф- фициенты, а к — константа. При тестировании доменов границы часто описыва- ются линейными неравенствами. Линейный домен. Домен, все граничные неравенства которого линейны. Нелинейный домен. Домен, у которого по крайней мере одно граничное нера- венство не линейно. Линейно зависимый. Два неравенства называются линейно зависимыми, если одно из них можно превратить в другое путем отбрасывания константы к и умножения всех коэффициентов а, на соответствующий множитель. Например, х + 2у >= 7 и Зх + бу < 5 линейно зависимы, поскольку, отбрасывая постоянные слагаемые и умножая первое неравенство на 3, мы получаем Зх+бу. Линейно зави- симые гиперплоскости параллельны друг другу. На предыдущем рисунке диаго- нальные границы были линейно зависимы Линейно независимый. Неравенства называются линейно независимыми, если они не являются зависимыми. Несколько неравенств линейно независимы, если ни одно из них не является линейно зависимым от любого другого. Границы, определяемые линейно независимыми неравенствами обязательно пересекаются. Линейно независимые точки. Наборы точек (то есть входные векторы) vp v2, v3,.... vp линейно независимы, если уравнение с^-ь c2v2 + c3v3+... + cpvp=0 имеет единс- твенное решение с3 = с2 = с3 =... = ср = 0 для всех коэффициентов. Если точки не яв- ляются линейно независимыми, то они линейно зависимы, и некоторые из них можно выразить через другие. Законченная граница. Граница, простирающаяся на +-оо по всем своим пере- менным. Мы будем считать границы законченными, если не оговаривается об- ратное. Наклоненная вверх граница на рисунке является законченной, поскольку простирается на +-<» по всем своим переменным. 1 Эго может быть необходимо из-за ограничений, накладываемых компьютерным методом пред- ставления чисел [JENG 94]. К примеру, функция, определенная для целых чисел, может не иметь точ- ных решений на границе. 2 Неплохо бы для начала запомнить акроним. — Примеч. перев.
Сегмент границы. Часть граничного неравенства между двумя или более доме- нами. Иначе говоря, один из краев домена. Как правило, граничное неравенство определяет сегменты границ для множества различных доменов. Незаконченная граница. Граница с одним или более разрывами. Наклоненная вниз граница на рисунке выше разорвана и, следовательно, незакончена. Разрывы, если они есть, лежат между узловыми точками; это значит, что они состоят из сег- ментов границ. Последовательное закрытие. Граница, для которой направление, в котором она закрыта (или открыта), сохраняется на всем ее протяжении. Мы будем в даль- нейшем считать закрытие границ последовательным, если не оговаривается об- ратное. Граница, отмеченная как последовательная на рисунке, имеет одно и то же направление закрытия на всем своем протяжении. Непоследовательное закрытие. Граница, для которой направление закрытия меняется по меньшей мере один раз на ее протяжении. Граница, отмеченная на ри- сунке как непоследовательная, закрыта. Изменения направления закрытия, если они есть, обычно происходят в узловых точках. Это означает, что в большинстве случаев направление закрытия меняется между сегментами границ. 7.3. Отношения и модель 7.3.1. Обоснование Я изменю обычный порядок изложения и начну с обоснования необходимости тестирования доменов и его семантики, поскольку предыдущие определения мо-
гут показаться читателю чересчур абстрактными. Тем не менее, я рассчитываю, что вы разобрались в этих определениях. Тестирование доменов основано на простой вычислительной модели, проил- люстрированной на рис. 7.1. Тестируемая система получает входной вектор, кото- рый затем проходит через процедуру сортировки. Все входные значения, лежащие за пределами заданных допустимых значений, отбрасываются или, если это воз- можно, корректируются. После этого процедура сортировки (вне зависимости от того, как она реализована) определяет, какому из нескольких условий удовлетво- ряет входной вектор. После выбора соответствующего условия вектор поступает для обработки в соответствующий этому условию узел обработки (это осущест- вляется, например, при помощи гипотетического оператора CASE), где и происхо- дит его обработка. При тестировании доменов нас интересует корректность про- цедуры сортировки и корректность гипотетического или реального оператора CASE, использующегося для направления входного вектора в соответствующий узел об- работки, а не корректность самой обработки для каждого случая. Это разграниче- ние впервые введено Хоуденом [HOWD76], При тестировании доменов мы полагаем, что процедура сортировки осу- ществляется при помощи системы неравенств, содержащих входной вектор. Это означает, что для каждого конкретного случая существует по крайней мере одна система неравенств, которая определяет удовлетворяющий этому условию до- мен. Таких систем неравенств может быть больше одной, если домены задаются в несвязанных областях. В качестве примера рассмотрим, как ВНС определил домены для подсчета ва- ших налогов, при условии, что вы холосты. Домен Процедура О < нал_доход =< $22100 налог = 0.15 х нал_доход
$22100 < нал_доход =< $53500 налог = $3315 + 0.28 * (нал_доход - $22100) $53500 < нал_доход -< $115000 налог = $12107 + 0.31 * (нал_доход - $53500) $115000 < нал_доход =< $250000 налог = $31172 + 0.36 * (нал_доход - $115000) $250000 < нал_доход налог = $79722 + 0.396 * (нал_доход - $250000) В приведенном примере фигурирует только одна входная переменная — нал_ доход (налогооблагаемый доход). Легко заметить, что определены пять1 доменов. Первые четыре состоят из двух неравенств каждый. Для них определены верхняя и нижняя границы. У последнего домена нет верхней границы1 2. В инструкциях по заполнению декларации говорится, что если ваш доход не превышает $100000, то вы не должны использовать эти неравенства. В этом случае вам надо пользо- ваться налоговыми таблицами. Исследуя налоговые таблицы, можно обнаружить расхождения между ними и уравнениями. Расхождение возникает из-за того, что в таблицах приводятся верхняя и нижняя границы для каждого входа и налог рассчитывается для величины верхней и нижней границы, округленной до бли- жайшего доллара. Формулы же (используемые лишь для дохода, превышающе- го $100000) точны, и налогоплательщик может сам решать, округлять ему налог или нет. Что же является в данном случае целью тестирования? Налоговые таблицы, так или иначе, должны применяться, и, следовательно, вам надо тестировать именно их. Если вы тестируете программу расчета налогов и используете домены, опре- деленные при помощи уравнений в вашей модели, для тестирования табличной реализации, то можете не заметить небольших ошибок в таблице — как правило, меньших $5. Если вы тестируете таблицу, а не уравнения, вы должны в соответс- твии с таблицей так построить уравнения, чтобы они корректно отображали доме- ны, приведенные в таблице. 7.3.2. Основы Описание компонентов графа и связанных с ними отношений не столь продуктив- но при тестировании доменов, как для большинства других методов; тем не менее, это позволяет понять суть метода, что необходимо при любой стратегии. Объекты (узлы). Домены, определенные для входного вектора. Отношение (связи). Определено отношение «смежный с». Смежный — это зна- чит имеющий общую границу. Условимся принимать за направление связи на- правление неравенства. Например, если А и В — смежные домены и А является закрытым доменом, стрелку надо рисовать от А к В. Вы можете выбрать и другой способ определения направления, это не принципиально, главное, чтобы вы были последовательны в своих действиях. Так же как для всех графических моделей, следует провести тесты, чтобы убедиться в правильности направления стрелок (вне зависимости от выбранно- го правила). Такая интерпретация принципа графового моделирования означа- ет, что мы должны проверить закрытость границ всех смежных доменов (то есть 1 На самом деле — шесть. Спецификация содержит ошибку и отличается от требований. Объясни- те, какая ошибка допущена? 2 Поскольку максимальная сумма взимаемого с нас налога не ограничена.
покрытие связей). Например, каждая из констант в определениях приведенных выше доменов ($22100, $53500, $115000 и $250000) фигурирует в двух различ- ных неравенствах и одном расчетном выражении. Ошибка, связанная с этими кон- стантами, может привести к нарушению смежности доменов. Вам придется про- тестировать отношения в обоих направлениях, чтобы убедиться, что ничего не пропущено и нет перекрытий доменов. Веса связей. Неравенства, определяющие границы между доменами. Так как домены могут встречаться в нескольких неравенствах, то между двумя доменами может существовать несколько связей. Для иллюстрации этого требуется как ми- нимум двумерное пространство. Вы можете моделировать это посредством одной связи для каждого неравенства. Неравенство (в пространстве с размерностью два или более) может являть- ся границей для множества доменов. Две линии, пересекающиеся на плоскости, определяют четыре области и, следовательно, четыре домена. Три неравенства на плоскости могут задать семь доменов’. Наша стратегическая задача — тестирова- ние неравенств, а не доменов. Веса узлов. Вычисления, соответствующие доменам. Заметим, что одному до- мену может соответствовать более одного вычисления. Домен может быть опре- делен таким образом, что он будет состоять из граничащих частей, или, даже из несвязанных частей. Примером может служить следующая спецификация. О < х =< 17 Процесс А 17<х = <34 Процесс В 34<х = <39 Процесс С 39<х = <44 Процесс А 44<х Процесс D Домен, соответствующий процессу А, состоит из двух несвязанных частей. Как нам его лучше исследовать? Я предпочитаю рассматривать каждую часть тако- го домена как самостоятельный субдомен, который обрабатывается совместно с некоторыми другими субдоменами (другими частями домена). Я придерживаюсь этого принципа, поскольку так или иначе нам все равно придется их тестировать. В дальнейшем помните, что все, сказанное о тестировании доменов, касается так- же и тестирования субдоменов (если они есть). Покрытие узлов'. Для осуществления покрытия узлов вы должны сделать как минимум четыре вещи: 1. Рассмотреть по меньшей мере одну контрольную точку в каждом домене, что- бы убедиться, что с помощью оператора CASE выбран надлежащий вариант об- работки, и, если сортировка проведена корректно, убедиться в правильности обработки. Это означает проведение как минимум одного теста для каждого домена. Однако один тест не может обеспечить надежную проверку процес- са обработки. Обработка домена может представлять собой целую програм- ' Число доменов определяемых к-неравенствами, растет стремительно с ростом размерности про- странства. (Определение возможного числа доменов представляет собой очень сложную математиче- скую задачу, которая носит название «проблема блина» в двухмерном пространстве и «проблема апельсина» в трехмерном пространстве.)
му, включающую в себя поток управления, потоки данных, потоки транзак- ций и другие средства. Используйте для проверки соответствующую модель1. 2. Для доменов, состоящих из субдоменов (как смежных, так и не смежных), убедитесь, что все требуемые части существуют и обрабатываются в соот- ветствии с требованиями. 3. Убедитесь, что домены не перекрываются. В одномерных и двухмерных пространствах это делается графически. В пространстве с размерностью три и более, используйте соответствующие алгебраические инструменты [WHIT95] (их описание лежит за пределами данной книги). В большин- стве случаев, однако, перекрытие доменов происходит на границах. 4. Убедитесь, что входное пространство является полным. Каждый входной вектор должен быть обработан, даже если эта «обработка» означает отбра- ковку ввода. В одномерном и двухмерном пространстве вы можете провес- ти эту проверку самостоятельно. В пространстве с размерностью три и бо- лее используйте соответствующие алгебраические инструменты [WHIT95] (их описание лежит за пределами данной книги). Как и в случае перекры- тия, большинство подобных ошибок возникает на границах доменов. Покрытие связей/ Ниже указано, в каком порядке следует его проводить. 1. Убедитесь, что все домены, которые должны быть смежными, на самом деле смежные, то есть имеют общее граничное неравенство. 2. Убедитесь в отсутствии лишних границ. В этом вам поможет стратегия тес- тирования доменов. 3. Убедитесь в корректности всех граничных неравенств. В этом заключается основная задача тестирования доменов. В качестве примера разработки модели тестирования доменов рассмотрим вариант формы 10402, строки с 32 по 38. У меня была задача построить пример, включающий как минимум две входные переменные. Вот мой вариант специфи- кации для строк 32-38. 32: Adjusted Gross Income (Скорректированный__Общий_Доход (СОД)) Служит входом в этом примере 33: 34: Стандартные отчисления Без проверки, полагается равным 0 В этом примере мы берем их 35: (СОД)-$6200 равными $6200 Заданные вычисления бе: Льготы Служит входом в этом примере 36: $2350 * Льготы В этом примере игнорируем верхний 37: нал_доход = Мах (0. С35-С36) предел $81350 Налогооблагаемый доход. Мы будем ' Проверка обработки может быть проведена в том числе путем тестирования домена, если, напри- мер, обработка представляет собой алгебраическое уравнение. Это можно рассматривать как проверку корректности вырожденного домена, заданного с помощью предиката равенства. [ AFIF92]. 2 Этот вариант сильно искажает бланк декларации, поэтому, пожалуйста, не используйте его в це- лях, связанных с уплатой налогов.
38: Таблица расчета налогов О < нал_доход =< $22100 $22100 < нал_доход =< $53500 $53500 < нал_доход -< $115000 $115000 < нал_доход -< $250000 $250000 < нал_доход для всех значений использовать таблицу расчета налогов налог = 0.15 * нал_доход налог = $3315 + 0.28 * (нал_доход - $22100) налог - $12107 + 0.31 * (нал_доход - $53500) налог = $31172 + 0.36 * (нал_доход -$115000) налог = $79722 + 0.396 * (нал_доход - $250000) Нашей задачей является разработка модели тестирования доменов, которую мы можем использовать для проверки корректности реализации таблицы нало- гов. Прежде всего нам надо выразить таблицу налогов через входные переменные (СЭД и Льготы). Проделайте это, заменяя входные переменные на соответствующие выражения, и затем, используя символическую подстановку, получите таблицу налогов. Я выполнил эти действия и вычеркнул несущественные для результата строки. Вот как выглядит моя перегруппированная модель: 32: СОД (Скорректированный_Общий_Доход) Вход бе: Льготы Вход 38: Налог, рассчитанный из таблицы расчета налогов Домен 1: налог =0.0 СОД-6200-2350 * Льготы <=0 Домен 2: налог = 0 15 * (СОД - 6200 - 2350 * Льготы) СОД - 6200 - 2350 * Льготы > 0 СОД - 6200 - 2350 * Льготы <= 22100 Домен 3: налог = 3315 + 0.28 * ((СОД - 6200 - 2350 * Льготы) - 22100)) СОД - 6200 - 2350 * Льготы > 22100 СОД - 6200 - 2350 * Льготы <- 53500 Домен 4: налог - 12107 + 0.31 * ((СОД - 6.200 - 2.350 * Льготы) - 53500)) СОД - 6200 - 2350 * Льготы) > 53500 СОД - 6200 - 2350 * Льготы <= 115000 Домен 5. налог - 31172 + 0.36 * ((СОД - 6.200 - 2,350 * Льготы) - 115000)) СОД - 6200 - 2350 * Льготы > 115000 СОД - 6200 - 2350 * Льготы <= 250000 Домен 6. налог = 79772 + 0.396 * ((СОД - 6200 - 2350 * Льготы) - 250000)) СОД - 6200 - 2350 * Льготы > 250000 Чтобы сделать это, я использовал функцию поиска и замены в текстовом ре- дакторе. Сначала я передвинул строку бе в начало. Затем'я удалил строки 33 и 34, поскольку в этом примере их значения считаются заданными и приведены в пер- воначальной модели. Далее я подставил СОД-6200 вместо С35, удалил строку 35 и упорядочил алгебраические выражения. Перед проведением подстановки я за- ключил выражения в скобки, чтобы избежать ошибок, таких как изменения знака из-за двойного знака «минус» и умножения выражения на константу, например, при вычислении переменной налог. Следующая подстановка была проведена для строки 36. Переменную Мах в строке 37 я удалил путем добавления другого доме- на, как вы можете видеть для случая отрицательного налогооблагаемого дохода. Затем я заменил переменную нал_доход и получил конечные выражения, которые и привел здесь (после небольшой перегруппировки для того, чтобы привести их
все к одинаковому виду). Затем я упростил алгебраические выражения для нало- гов и получил в результате следующую модель: 32: СОД (Скорректированный_Общий_Доход) Вход бе: Льготы Вход 38: Налог, рассчитанный из таблицы расчета налогов Домен 1: налог = 0.0 СОД <• 6200+2350Льготы Домен 2: налог = 0.15СОД - 352.5Льготы - 930.0 СОД > 6200 + 2350Льготы СОД <= 28300 + 2350Льготы Домен 3: налог = 0.28СОД - 658.0Льготы - 4609.0 СОД > 28300 + 2350Льготы СОД <= 59700 + 2350 Льготы Домен 4: налог = 0.31СОД - 728.5Льготы - 6400.0 СОД > 59700 + 2350Льготы мСОД<=121200+2350Льготы Домен 5: налог = 0.36СОД - 846.0Льготы - 12460 СОД > 121200 + 2350Льготы СОД <= 256200 + 2350Льготы Домен 6: налог = 0.396 СОД - 930.6Льготы - 21683.2 СОД > 256200 + 2350Льготы На рис. 7.2 показан возможно более наглядный способ представления этих доме- нов. В одномерном и двумерном пространстве будет не лишним изображать домены графически, подобно тому, как это сделал я. Границы доменов представляют собой несколько параллельных линий. Это типичные домены, встречающиеся на практи- ке. Тем не менее, нам потребовалось выполнить алгебраические преобразования, для того чтобы упростить эти границы и выразить их через входные переменные. Интерпретация предикатов. Символическая подстановка, проделанная выше, для того чтобы выразить домены через входные переменные, называется интер- претацией предикатов. Любое неравенство имеет вид предиката, который может принимать значение ИСТИНА или ЛОЖЬ. Предикат мы интерпретируем в терминах входных переменных. Зачем все усложнять, интерпретируя предикаты границ доменов? Почему бы нам не работать непосредственно со строками спецификации ВНС? Дело в том, что в этом случае у вас уже не будет модели для тестирования доменов, это будет модель потока управления. Нашей же целью является проверка корректной реа- лизации граничных предикатов (или их аналогов в коде). Наша конечная модель является избыточной. Граничные неравенства появ- ляются в ней дважды (по одному разу для каждого задаваемого ею домена). Эта модель неизящна, и вероятность того, что программист построит вычисления та- ким образом достаточно мала. Программист, проанализировав требуемые вычис- ления, организует их более эффективно (то есть так, чтобы их было проще сопро- вождать), и вместо промежуточных вычислений, заданных в спецификации, он, возможно, реализует нечто от них отличное, но, по всей вероятности, им эквива- лентное. И в этом все дело. Анализ, который мы проводим для разработки тес- тов доменов, имеет совершенно иные задачи, в отличие от задач, стоящих перед программистом, и поэтому наши ошибки тоже, скорее всего, будут отличаться от ошибок разработчика. У нас, тестировщиков, собственные ошибки.
Домен СОД (Тысячи) Лыоты « 1 ® Ouf’awZQ Dane i»3 g Омыт 4 Ш Canute SL teiMlsS Рис. 7.2. Домены для неравенств в налоговой декларации Основной аргумент в пользу проведения интерпретации предикатов — это обеспечение независимой проверки рациональности спецификации. Я допускаю, что спецификация содержит множество промежуточных вычислений на пути пре- образования входных данных в выходные. Подобные промежуточные вычисле- ния зачастую несущественны и являются всего лишь видением того, как долж- на быть запрограммирована спецификация, — что-то наши программисты могут и проигнорировать. Наша задача не ограничивается независимой проверкой работы программиста. Если проводимое нами моделирование выявляет противоречия и неопределенности в спецификации доменов (что часто и происходит), мы не зря едим свой хлеб. Интерпретация предикатов обычно не очень сложна. В большинстве случа- ев вам не надо проводить ее совсем, поскольку домены изначально выражаются через входные переменные. Если вам все же приходится это делать и если ваши предикаты достаточно просты, используйте ваш текстовый редактор подобно тому, как это делал я (однако не забывайте заключать подставляемые выражения в скобки, чтобы избежать различных алгебраических ошибок при подстановке). Если текстовый редактор не справляется, используйте редактор формул. Мне хва- тает моего калькулятора НР-28С. Если для вас это затруднительно, используйте соответствующий математический пакет. 7.3.3. Анализ неопределенностей и противоречий Приблизительно 30 % ошибок являются следствием некорректных требований. Цена таких ошибок высока, поскольку они проявляются лишь тогда, когда про-
грамма начинает эксплуатироваться. Около 5 процентов ошибок происходят из-за неверного определения доменов1. Вопреки широко распространенному мифу, не существует какого-то одного превалирующего типа ошибок. Относительная час- тота возникновения большинства ошибок не превышает 3 процентов, то есть 5 процентов — высокий показатель и на поиск ошибок в доменах имеет смысл тра- тить время. В программе необходимо исключить внутренние противоречия. Все ее функ- ции должны быть согласованы друг с другом. Программа также не может быть не- определенной. Она всегда должна выполнять какие-либо действия над входными данными. Спецификации, однако, бывают и неопределенными и противоречи- выми. Когда программист реализует такую неопределенную или внутренне про- тиворечивую спецификацию, он или она должны сознательно или несознатель- но разрешать эти неопределенности и противоречия. Ошибки объясняются тем, что неопределенности и противоречия обычно не удается распознать, и тем что их разрешение обычно происходит подсознательно. Модель тестирования доменов, а также анализ, необходимый для построения этой модели, эффективны при про- верке спецификаций на неопределенности и противоречия. Неопределенность доменов. Спецификация набора доменов является неопре- деленной, если этот набор доменов не покрывает все входное пространство. Противоречивость доменов. Два домена противоречивы, если они перекрываются. Первое место, где стоит искать неопределенности и противоречия, — это гра- ницы между доменами. Рассмотрим пример: Домен 3: СОД > 28300 + 2350Льготы СОД <= 59700 + 2350Льготы Домен 4: СОД >= 59700 + 2350Льготы СОД < 121200 + 2350Лыоты Домен 5: СОД > 121200 + 2350Льготы СОД <- 256200 + 2350Лыоты Граница между доменами 3 и 4 противоречива, поскольку оба они одновремен- но закрыты на границе СОД = 59700 + 2350Льготы. Граница между доменами 4 и 5 не определена, так как входные значения для СОД = 121000 + 2350Льготы отсутствуют в спецификации. Если у вас есть спецификация интерпретированной границы домена, вам надо проверить ее на предмет наличия неопределенностей и противоречий. Большинство из них легко могут быть выявлены при проверке. Для одной и двух входных переменных вы сможете выполнить это графически. Для трех и более входных переменных используйте соответствующие алгебраические инструмен- ты [WHIT95], 1. Все ли входные значения в диапазоне от -о» до +°° включены? Если это не так, то существуют ли механизмы, запрещающие ввод в систему значений 1 Эта оценка занижена для современного программного обеспечения, поскольку утверждение ос- новано на данных почти двадцатилстней давности (в 1994 году). В то время как методы компонентного тестирования совершенствовались, относительная частота возникновения ошибок в требованиях воз- растала. Я не удивлюсь, если доля ошибок доменов в среднем окажется порядка 10 а для некоторых программ и всех 30 %.
больше верхней границы и меньше нижней? Проведите специальную про- верку для нулевых значений. Спецификация в подразделе 7.3.1 не опреде- лена. Объясните, почему. 2. Последовательно ли закрытие для всех переменных и всех границ доменов в диапазоне от -<* до ч «•? Если это не так, то должно быть несколько (как ми- нимум два) неравенств, определяющих одну и ту же границу, но в различных областях входных значений, для различных направлений закрытия и вклю- чающих по меньшей мере одну переменную. Сгруппируйте эти наборы и про- верьте их на предмет наложения закрытий и/или зазоров между ними. Ниже приводится пример, в котором закрытие противоречиво и не определено. Домен 3: налог = 0.28СОД - 658.ОЛьготы - 4609.0 СОД >= 28300 + 2350Льготы. 0 < Льготы < 4 СОД > 28300 + 2350Льготы. 4 <= Льготы < 7 СОД >= 28300 + 2350Льготы. 7 < Льготы <= 10 СОД > 28300 + 2350Льготы СОД <- 59700 + 2350Льготы 3. В одномерных и двумерных пространствах нарисуйте все заданные доме- ны на одном рисунке, построив графически решения уравнений, определя- ющих границы для каждого из доменов. На следующем рисунке демонстри- руется неопределенность для входных значений, меньших 7, и перекрытие доменов 1 и 2. Помните, что неопределенности и противоречия чаще всего встречаются в определении границ, поэтому вы должны быть уверены, что проверили закрытие каждой границы. 4. А как насчет пространства с размерностью три и более? В этом случае не- обходим алгебраический анализ, см. [WHIT95]. Вы, возможно, сможете решить задачу анализа трехмерных моделей в лоб или при помощи эврис- тических методов, но вряд ли вам что-нибудь сможет помочь разрешить ма- тематические аспекты данной проблемы. Созданные к 1995 году коммер- ческие инструменты не могут уверенно подтвердить непротиворечивость и однозначность спецификаций доменов. Организации, которым регуляр- но бывает нужен подобный анализ, привлекают для этих целей экспертов и разрабатывают собственное программное обеспечение. Х = 7Х>=7&Х<44 X = 44 Неоднозначность Противоречие Домен 3 Х>= 50 7.3.4. Нелинейные домены В этом разделе я поделюсь хорошими новостями, а также хорошими новостями, которые могут показаться плохими, но не для всех, и отличными новостями. 7 Зак. 770
1. Хорошие новости. Хорошей новостью является то, что нелинейные домены (то есть домены как минимум с одной нелинейной границей) на практике встречаются не слишком часто. Ранние исследования [СОНЕ78] выявили в коде языка COBOL около 85 процентов линейных предикатов. Мы имеем дело в основном с лилейным миром. 2. Хорошие новости, которые могут показаться плохими (не обязательно). Проблему линейности в нашем случае надо рассматривать не как простую алгебраическую линейность, а в более широком смысле линейности век- торных пространств. Полиномы первого порядка линейны в этом широком смысле. Поскольку любая приличная функция может быть аппроксимиро- вана полиномами, то выбором подходящей аппроксимации можно свести задачу тестирования нелинейных доменов к задаче тестирования линейных доменов, хотя и ценой увеличения размерности. Нелинейные граничные уравнения нередко можно линеаризовать определенными преобразовани- ями. Это в первую очередь касается гипербол, экспоненциальных, степен- ных и логарифмических функций. Аппроксимация функций полиномами первого порядка встречается довольно редко, так как неэффективна с точ- ки зрения вычислимости. Однако благодаря большой производительнос- ти современных компьютеров эта проблема стоит гораздо менее остро, чем принято считать. Выбирайте сами, чего вы хотите, вычислительной эффек- тивности или тестируемости. 3. Отличные новости. Отличные новости [JENG94] состоят в том, что если вам нужно определить только наличие ошибки, а не описать ошибку (на- пример, вид доменной ошибки), и при этом вы хотите исходить из рассчи- тываемого риска сокрытия некоторых ошибок [AFIF92], тогда проблем не- линейных границ доменов просто нет (в большинстве случаев). 7.4. Методы 7.4.1. Основы Существует масса стратегий тестирования доменов [AFIF90, AFIF92, CLAR82, СОНЕ78, JENG94, НАОМ87, PERE85, WHIT78A, WHIT80A, WHIT85B, WHIT90, ZEIL83, ZEIL89]. Мы не будем рассматривать их все. Если вы занима- лись программированием, то вы, безусловно, знаете основы стратегий тестирова- ния доменов. Если вы занимались программированием непродолжительное вре- мя, то вы использовали эвристические методы тестирования доменов. Прежде чем прейти к рассмотрению эффективных стратегий, давайте обсудим причины несовершенства эвристических стратегий. 1. Тестирование экстремальных точек. В соответствии с этой стратегией лю- бой численный ввод должен быть протестирован в окрестности минимально- го и максимального значения этого ввода. Эта эвристическая стратегия имеет множество названий, таких как тестирование граничных значений [MYER79],
тестирование экстремальных значений и тестирование особых значений, [HOWD80], Как подмечено Ричардсоном [RICH85] и многими другими, все эти эвристические стратегии относится к тестированию доменов. Основное от- личие между формальным тестированием доменов и эвристическим тестиро- ванием доменов (общепринятым в течение десятилетий) заключается в боль- шей эффективности первого и в том, что формальное тестирование позволяет узнать больше о найденных ошибках при помощи меньшего числа тестов. 2. Тестирование комбинаций экстремальных точек. Следующая стратегия ти- пична и необычайно популярна (но плохо управляема). Согласно ей, необ- ходимо проверить комбинацию экстремальных точек. Несмотря на то, что эта стратегия поддерживается коммерческими продуктами, позволяющими автоматически генерировать тесты, она в принципе ущербна, что мы и уви- дим в дальнейшем. 7.4.2. Недостатки комбинирования экстремальных точек «Стратегия» комбинирования экстремальных точек, если ее можно так назвать, подразумевает существование наибольшего и наименьшего значений для каж- дой входной переменной. Предполагается, что все значения больше максимума и меньше минимума программа исправит или запретит. Очевидно, минимальные и максимальные значения определяют (отчасти) границы доменов, и стратегия направлена в первую очередь на тестирование границ доменов, а затем на провер- ку значений, лежащих чуть выше максимума и чуть ниже минимума. Это в про- странстве с размерностью один. В двумерном пространстве, согласно этой стра- тегии, необходимо проверить комбинацию экстремальных точек. Если я условно назову четыре актуальных случая для каждой переменной соответственно «ниже», «min», «max» и «выше», то в соответствии с этой стратегией для двух переменных нам надо проверить: (нижеА, нижеВ), (нижеА, minB), ... (вышеА, вышеВ), все- го 16 тестов, плюс еще один для типичных значений. Для п входных переменных число тестовых вариантов вырастет до 4n + 1. Какой тип ошибок мы здесь рассчитываем обнаружить? Обработка, что бы она собой ни представляла, должна задавать функциональное отношение между вход- ными переменными. Существует два варианта функциональных отношений меж- ду входными переменными: выходная функция, выраженная через эти перемен- ные, или граница домена, выраженная через эти переменные. 1. Функция. Вычисляемая функция может быть или верной, или неверной. При тестировании комбинаций мы предполагаем отсутствие ошибок, за ис- ключением особенных комбинаций (экстремальных случаев), поскольку для других комбинаций входных значений программа корректна. Иначе го- воря, корректная обработка и обработка комбинации экстремальных зна- чений, содержащая ошибки, соответствуют различным доменам. Если дело в этом, то нам лучше проверить границы доменов. 2. Граница домена. Входные переменные могут фигурировать в одной и той же (интерпретированной) границе домена. То есть возможны два вариан-
та — либо входные переменные используются в описании границы, либо нет. Если нет, то они независимы. Между ними не существует функциональных отношений, мы предполагаем наличие ошибки, которая создает отношение на пустом месте. В таком случае это не ошибка, а вредительство. Если функ- циональное отношение существует, то его то нам и надо проверять, а тести- рование ряда комбинаций критических значений не даст нам никакой ин- формации об этом отношении. В примере на рис. 7.3 я применил эвристическую комбинационную страте- гию и получил заштрихованные точки. У нас есть три домена, границы которых изображены сплошными линиями Только восемь контрольных точек — смеж- ные с критическими точками, лежащими на верхней границе — могут сказать нам что-либо о корректности границ доменов. Тесты не скажут нам ничего о коррект- ности нижней границы. Предположим, у нас есть ошибка, в результате которой реализуются два домена с границами, показанными пунктиром. Вместо грех доме- нов, мы получаем четыре, и кто знает, какая обработка будет им соответствовать? Тестирование комбинаций экстремальных точек не выявит эту ошибку. Рис. 7.3. Функциональное отношение между входными переменными Однако, может возразить предполагаемый оппонент, мы знаем, что домены су шествуют и что нам надо протестировать вводы в области значений Х = 6иУ = 6и их комбинации! Уже лучше, но все равно недостаточно хорошо. Эта предлагаемая поправка добавит 12 тестов, но все равно не сможет выявить ошибочное пересече ние 1раниц. В итоге мы приходим к выводу, что единственный способ протестиро- вать функциональное отношение — это тестировать функциональное отношение. И предположение о наличии ошибки, которая создает отношение на пустом мес- те — плохое предположение. Тестирование комбинаций экстремальных точек — это не лучший способ тестиро- вания доменов в n-мерном пространстве. Ок приводит к необходимости проведения массы тестов, большинство из которых бессмысленны и/или обманчивы. В преды-
душем примере мы провели 29 тестов, но так и не обнаружили ошибку. Правильная стратегия выявит эту ошибку всего за 4 теста. Самое плохое в рассматриваемой стра- тегии — это то, что число тестов растет экспоненциально с увеличением числа вход- ных переменных. Следовательно, покрытие невозможно даже при наличии автома- тизации. Для 50 входных переменных только очень небольшая часть чудовищного числа комбинаций (1.2677Е30, или4Е19лет тестирования при длительности теста— 1 миллисекунда) может быть проверена, и, следовательно, выбор проверяемых ком- бинаций будет совершенно произволен. Правильно организованное стохастическое тестирование обнаружит большее число ошибок и скажет вам больше о надежности программного обеспечения. В то же время грамотное тестирование доменов облада- ет существенно большими возможностями при меньших затратах. 7.4.3. Слабая стратегия 1x1, одномерное пространство Первая стратегия (которая будет вами наиболее часто использоваться) — это сла- бая стратегия 1x1. Она называется «слабой», поскольку в ней предусматривается раз- работка всего лишь одного набора тестов для каждою граничного неравенства, вместо того, чтобы разработать подобный набор для каждого сегмента границы, а «1 х 1», так как она требует одну точку НА и одну точку ВНЕ для одною 1раничного неравенства. На рис. 7.4 показаны все возможные ошибки для одномерной границы доме- на. В соответствии со стратегией, требуется по два теста на каждую границу (точ- ка в одномерном пространстве) — проверка одной точки НА и одной точки ВНЕ. Я проиллюстрировал это на примере закрытой границы. Предлагаю вам в качест- ве упражнения самостоятельно убедиться, что стратегия работает для любой ком- бинации открытых и закрытых границ. Приведенные ниже случаи моделируют все возможные ошибки в одномерных границах доменов. 1. Ошибка закрытия. Граница открыта в то время, когда должна быть закрыта, и закрыта в то время, когда должна быть открыта. Тест точки ВНЕ выявит эту ошибку, поскольку ввод будет обработан как домен В, вместо того что- бы обрабатываться как домен А. Это работает, если только на границе нет случайной корректности. 2. Граница сдвинута влево. Точка ВНЕ будет обработана как домен В, вместо того чтобы обрабатываться как домен А. 3. Граница сдвинута вправо. Точка НА должна обрабатываться как домен А, но вместо этого будет обработана как домен В. Этот тест не дает информа- ции, связана ли эта ошибка с закрытием или со сдвигом вправо, а лишь ука- зывает на наличие ошибки. 4. Пропущенная граница. Обе точки НА и ВНЕ обрабатываются одинаково, хотя должны обрабатываться по-разному. 5. Лишняя граница. Дополнительная граница делит первоначальный домен на два домена. Наличие еще одной границы должно проявляться в видимом различии в обработке, в противном случае, мы не сможем ее обнаружить. Сравнение двух процессов обработки для точек, принадлежащих изначаль- ной границе, должно выявить это различие.
В ___ ф _А_ Корректный домен А здкрь. i Контрольная точках .очкаНА —в--------------------&------------....а...... Ошибка, закрытие домена В Контрольная точка х точка ВНЕ Ошибке оаница сдвинута влево Контрольная точка х, точка НА ;---В_------.---.------*- Ошибка. граница вдвинута вправо X X test points on г off ___В____________________-.__________ _______А Ошибка граница пропущена Контрольная точка х точка НА^( Ошибка лишняя граница Конт рог иная -очках (точка НА) v А А Рис. 7.4. Ошибки в одномерном пространстве (закрытый домен) Сравним эту стратегию с эвристической стратегией тестирования доменов для одномерного случая. Эвристическая стратегия предусматривает тестирование точки НА, точки ВНЕ, а также точек вблизи границы, но по другую сторону от нее («противоположность» точке ВНЕ) — то есть три теста для проверки одной гра- ницы, в то время как стратегия 1 х 1 требует лишь два теста. Неплохо. Мы умень- шили число тестов на треть и ничего при этим не потеряли; выигрыш в простран- стве с большей размерностью будет гораздо более существенный. Применим данную стратегию для случая нескольких границ. Спецификация доменов, приведенная в подразделе 7.3.1, после представления каждой границы в виде одного выражения выглядит так: Домен нал_доход нал_доход нал_доход над_доход нал_доход нап_доход нал_доход нал_доход нал_доход > О -< 22100 > 22100 =< 53500 > 53500 =< 115000 > 115000 =< 250000 > 250300 Тесты НА=0 ВНЕ=0.00001 НА=22100 ВНЕ=22100.00001 НА-22-100 ВНЕ 22100 0с-0и1 НА=53500 ВНЕ=5350С.00001 НА-53500 ВНГ-53500.00001 НА-115000 ВНЕЧ15000.00001 НА-1 ] 5000 ВНЕ-Н-бООО. 00-101 НА-250000 ВНЕ-250000.00001 НА-250000 ВНЕ -250000.U0001 У нас есть пять доменов (на самом деле шесть) и пять определенных границ, которые мы проверяем при пемощи 10 тестов: примитивной стратегии в то же са- мое время требуется 15 тестов, и при этом она не даст нам ничего нового.
7.4.4. Слабая стратегия 1x1, пространство с размерностью два и выше Наша первая задача — определить, есть ли у нас ошибки, связанные с доменами. Границы, не содержащие ошибок, не требуют тестирования. Для границ, содержащих ошибки, будет полезно понять, что же неправильно в их реализации. Для этого нам необходима более сильная стратегия (N х 1, см. ниже). Для более узкой задачи (и бо- лее полезной для быстрой оценки), когда требуется определить, есть ошибки или их нет, стратегию 1x1 можно использовать в пространстве размерности два и более. Я называю ее «слабой» стратегией 1x1, поскольку делаю следующие предпо- ложения: каждая граница простирается до ±о», границы не содержат разрывов, и закрытие последовательно вдоль всей длины границ. Данная стратегия не ограни- чена требованием линейности границ или, скажем, функциями, определенными для вещественных чисел, — она применима без исключений к фактически любым доменам, которые могут определяться в программах. Эта стратегия предусматривает тестирование одной точки НА и одной точки ВНЕ для каждого граничного неравенства, то есть тестирование двух точек, нахо- дящихся так близко друг к другу, чтобы они могли удовлетворять определению точек НА и ВНЕ. Заметим, что точка НА может и не лежать непосредственно на границе, если компьютерная или языковая система представления чисел не дает такой возможности. Точка НА всего лишь должна удовлетворять условиям грани- цы. Такая ситуация продемонстрирована на следующем рисунке. Правильная граница показана на нем сплошной линией. Направление ее за- крытия, как обычно, отмечено штриховкой. Одна из возможных ошибочных ре- ализаций показана пунктирной линией. Заметим, что мы не ограничены линей- ными границами доменов. Попробуйте изменить расположение этой кривой, и убедитесь, что в любом случае (за одним исключением, отмеченным ниже) либо точка НА будет лежать в домене В, либо точка ВНЕ будет лежать в домене А. В
Исключение иллюстрирует данный рисунок. Ошибочная граница проходит на нем как раз между выбранными точками НА и ВНЕ. Прежде чем перейти к рас- смотрению способов обнаружения данной ошибки, мы должны оценить вероят- ность ее возникновения. А она мала, поскольку мы имеем дело со случайными ошибками, а не с вредительством. Ошибки доменов в большинстве случаев доста- точно масштабны и обладают явно выраженными симптомами. Например, возле десятичной точки пропущен коэффициент, или она поставлена не туда куда надо, пропущена или изменена константа, или даже пропущено целое выражение. В ре- зультате подобных ошибок происходит довольно существенное искажение оши- бочной границы. Как мы можем от этого защититься? Выбором точек НА и ВНЕ настолько близко друг к другу, насколько это только возможно. У нас нет гаран- тии, что ошибочная граница не попадет в зазор между выбранными контрольны- ми точками, но вероятность этого мала. Но насколько действительно мала эта вероятность? Теория может дать качест- венную оценку [ AFIF92, JENG94], Дженг и Ваюкер [JENG94], основываясь на тео- ретических исследованиях, приводят убедительные аргументы, подтверждающие, что она ничтожна. Любое тестирование характеризуется вероятностью, с которой оно пропустит серьезные ошибки. Аргументы Дженга и Ваюкера могут быть до- статочно хороши для тестирования обыкновенного программного обеспечения, но для жизненно важных программ или для программ, создающих серьезные фи- нансовые документы, может возникнуть желание избежать риска и использовать более сильные (и требующие гораздо больших затрат) методы, гарантирующие, что подобные коварные ошибки не останутся незамеченными. Давайте применим стратегию 1 х 1 к следующему примеру. Домен 4: налог = 0.31С0Д - 728.5Льготы - 64С0.0 СОД > 59700 + 2350Льготы СОД <= 121200 + 2350Льготы Мы об этом не говорим, но число льгот (Льготы), очевидно, должно быть цело- численным и быть больше нуля. Мы начнем с выбора точки НА, поскольку это про- ще всего сделать. Выберете любую точку, удовлетворяющую границе домена. У нас есть две границы. Для второй границы мы имеем СОД = 121200 + 2350Льготы, поэтому, выбирая, например, значение Льготы = 5, получаем СОД = 132950. Нам надо, чтобы точка ВНЕ лежала совсем близко. В данном приложении наименьшей различимой величиной является пенни, поэтому значение, меньшее на два порядка, будет удов- летворять нашему условию. То есть получаем СОД = 132950.0001 и Льготы = 5. Заметим, что вы вправе выбирать значение точки ВНЕ настолько близкое, на- сколько вам позволяет система представления чисел, чтобы не нарушались рас- четы при округлении или вследствие ошибки компьютера. К примеру, вы може- те выбрать значение СОД = 132950,0000000С0001, при условии, что ваш компьютер и/или язык поддерживают вычисления с плавающей точкой до такой значащей цифры. Это полезно, поскольку уменьшается вероятность пропустить ошибку, вкравшуюся между точек НА и ВНЕ. С другой стороны, если система представле- ния чисел поддерживает вычисления (для последнего примера) только до десятой значащей цифры, то ваши точки НА и ВНЕ сведутся, по сути, к одной точке, и вы уже не будете использовать данную стратегию. Я предлагаю вам самим разрабо-
тать тесты для других границ этого домена и рассчитать ожидаемые значения для спроектированных вами тестов. 7.4.5. Вырожденный случай В n-мерном пространстве вырождение возникает, если домен определяется как область с размерностью меньшей, чем п. А и В — смежные домены и оба открыты по отношению к показанной на рисунке границе. 'ч Точка ВНЕ X. для В и С 'к Домен В о*крьп Точка ВНЕ для А и С -* Точка НА для А, В и С Домен А открыт х Домен С закрыт Линия С обозначает границу и представляет собой отдельный домен. Согласно определению, граница должна быть закрыта. Стратегия 1x1 будет здесь работать, если вы корректно интерпретируете составляющие элементы. Домен А открыт, по- этому мы берем точку НА на границе, а точку ВНЕ внутри А. Для В тоже надо вы- брать точку НА, но мы можем взять ее той же самой, что и для А. Точка ВНЕ для В лежит внутри В. Как насчет С? Она закрыта, поэтому, согласно определению, точка ВНЕ должна лежать снаружи. Снаружи чего? Снаружи С и, следовательно, в обоих доменах А и В. Повторяюсь, точки мо.ут быть общими. Таким образом, в случае вырождения нам не нужны дополнительные тесты, если мы уточним, что мы подразумеваем под «точкой ВНЕ» в данной ситуации. 7.4.6. Стратегии более высокого порядка для пространства с размерностью два и более 7.4.6.1. Для чего нужны стратегии более высокого порядка? Существуют две причины для использования стратегий более высокого порядка. Чтобы быть уверенными, что ошибки границ различных типов не могут остаться не- замеченными для выбранных точек НА и ВНЕ базовой стратегии 1 х 1 и чтобы полу- чить информацию об ошибке, выявленной при помощи более простой стратегии. На самом деле у нас есть три причины, чтобы обсудить стратегии более высокого поряд- ка. В дополнение к первым двум причинам мы можем использовать стратегии более высокого порядка, для того чтобы оценить их вклад в тестирование в целом. 7.4.6.2. Безопасность тестирования Все стратегии более высокого порядка требуют большего числа контрольных то- чек, существенно большего. В большинстве случаев число дополнительных тестов,
приходящихся на одну границу, пропорционально размерности пространства. Если b — число границ, то стратегия 1x1 подразумевает проведение 2Ь тестов. Все более надежные методы требуют уже порядка Ьхп тестов, где п — размерность про- странства. Это гораздо хуже, но все равно не так плохо, как в случае примитивной стратегии, основанной на комбинации экстремальных точек, которая предполага- ет проведение тестов. Ситуация осложняется с ростом размерности, то есть вероятность пропустить ошибку, вкравшуюся между выбранными контрольными точками, растет с ростом размерности. Тем не менее, в 1995 году мы не располагали надежной статистикой для количественной оценки риска, а могли пользоваться лишь теоретическими исследованиями. Афифи с соавторами [AFIF92] продемонстрировали, что для полной уверен- ности в отсутствии ошибок, вкравшихся между выбранными точками НА и ВНЕ, а также для проверки на наличие множества других разных ошибок доменов вам необходимо п + 2 грамотно подобранных тестов на одну границу (слабое предпо- ложение). Как минимум, одна из точек должна быть точкой НА и одна должна быть точкой ВНЕ. Особенности контрольных точек (то есть что кроется за слова- ми «грамотно подобранный»), а также алгоритмы выбора этих точек лежат за рам- ками данной книги, но подробно изложены в [AFIF92], 7.4.6.3. Типы ошибок доменов Из трех целей, преследуемых при рассмотрении стратегий более высокого по- рядка, вторая и третья могут быть достигнуты при исследовании стратегии N х 1 [СОНЕ78]. N х 1 — приемлемая стратегия, которую можно использовать для диа- гностики природы ошибок в случае, если вы определили что ваша граница содер- жит ошибки. Она также помогает понять суть тестирования доменов и природы ошибок в целом. И, наконец, в любой специализированной литературе, описыва- ющей тестирование доменов, предполагается, что вы знакомы с этой стратегией. Применение стратегии N х 1 позволяет проводить диагностику ошибок, по- скольку, выбирая п точек НА, мы можем убедиться в корректности граничной гиперплоскости с размерностью п-1 в n-мерном пространстве (например, линии в двухмерном пространстве и поверхности в трехмерном пространстве). Мы можем рассматривать возможные варианты ошибок доменов в про- странстве с размерностью два и более для случая, когда все границы доменов линейны. В сущности, тестирование доменов представляет собой одну из не- многих областей, где можно описать ошибки на языке математики. Данная стратегия требует наличия п точек НА и одной точки ВНЕ для n-мерного про- странства. 1. Ошибка закрытия. Граница, которая должна быть открытой, реализована как закрытая, а граница, которая должна быть закрытой, реализована как открытая. Мы будем рассматривать случай закрытых границ, а анализ от- крытых оставим в качестве упражнения. Тестирование одиночной точки НА выявит эту ошибку, если на границе нет случайной корректности. Ошибка закрытия — это наиболее часто встречающаяся ошибка доменов.
В 1А. Методы 203 ESS ПРАВИЛЬНО A Ж1 НЕПРАВИЛЬНО 2. Сдвиг домена «вверх» или «вниз». В одномерном пространстве эта ошибка эквивалентна сдвигу влево или вправо. Сдвиг домена возникает вследствие ошибки в постоянном слагаемом неравенства: слишком большое или слиш- ком маленькое значение, или смена его знака. Это относится к п-мерному пространству. В отсутствии сдвига (корректная реализация) точка НА об- рабатывается как домен А, а точка ВНЕ как домен В. После сдвига вверх все три точки будут обрабатываться как домен А. ТОЧКА ВНЕ ПРАВИЛЬНО ТОЧКИ НА"А ГРАНИЦА СДВИНУТА ВВЕРХ в а Япредлагаювамсамостоятельнопроверить.чтостратегияМ х 1 вдвухмерном пространстве работает для всех видов сдвига (слишком большое, слишком маленькое значение или смена знака константы), для открытых и закрытых доменов. Сдвиги доменов, как правило, довольно значительны. Наиболее вероятной причиной возникновения сдвига является грубая ошибка F 1р2, например отсутствие десятичной точки или ее неправильное положение. Однако простая перестановка цифр в числе может привести и к небольшим сдвигам. Поэтому так важно выбирать точку ВНЕ как можно ближе к границе. 3. Поворот домена. В одномерном пространстве этому нет аналога, но эта ошибка встречается в пространстве с размерностью два и более. Поворот домена возникает вследствие какой-либо ошибки в коэффициентах тести- руемого неравенства.
Я повернул границу домена против часовой стрелки. В отсутствие поворота точка ВНЕ обрабатывается как домен В. После поворота эта точка попадает в домен А, и, следовательно, мы получили ошибку. Поворот домена является следствием ошибки в коэффициентах (в ли- нейных неравенствах), и, подобно сдвигу, он скорее будет большим, нежели маленьким. И точно так же, выбирая точку ВНЕ как можно ближе к границе, мы можем повысить чувствительность к маленьким сдвигам. 4. Лишняя граница. Стратегия N х 1 применима также и для поиска лишних границ. Вместо двух доменов возникают четыре. Предположим, лишней границе соответствует некоторые различия в процессе обработки, так что мы можем отличить, скажем, домен А от домена А'. Вч В' ТОЧКА ВНЕ | А—А' ТОЧКИ НА " Сравнение двух точек НА, выбранных гак, чтобы новая граница проходила между ними, выявит расхождение. Стратегия N х 1 слепа к лишним границам, которые не приводят к изменению обработки Однако это не смертельно, поскольку пользователь также их не заметит. 5. Пропущенная граница. Сравните любую из точек НА с точкой ВНЕ. В ре- зультате отсутствия границы домены А и В будут обрабатываться одинако- во (но мы не можем сказать, будет ли это обработка соответствовать доме- ну А или домену В). ТОЧКИ НА К ТОЧКА ВНЕ 7.4.6.4. Иллюстрация стратегии N х 1 Какие контрольные точки нам надо взять? Для слабой стратегии N х 1, где мы тестируем граничные уравнения, а не сегменты границ, выбирайте точки НА как можно дальше друг от друга, а точки ВНЕ посередине между ними. Вот некоторые комментарии для случая размерности большей, чем два. 1. Точки НА должны быть линейно независимы. К примеру, в трехмерном пространстве они не могут быть коллинеарными, то есть лежать на одной линии. В четырехмерном пространстве, где границы объемны, точки не мо- гут быть компланарны. Имеет смысл выбирать точки НА рядом с узлами доменов, поскольку узловые точки доменов всегда независимы.
2. Точки ВНЕ надо выбирать рядом с центром тяжести точек НА. Для линий берите середину между точками НА. Для плоскостей выбирайте точку, ле- жащую в середине треугольника, построенного на точках НА, то есть как можно ближе к точке, равноудаленной от вершин треугольника. Применим стратегию N х 1 для тестирования верхней границы домена 4. Донен 4: налог = 0.31СОД - 728.5Льготы - 6400.0 СОД > 59700 + 2350Льготы СОД <- 121200 + 2350Лыоты Число льгот (Льготы) не может быть отрицательным, поэтому мы выбираем ноль в качестве нижней границы. Здесь не задан верхний предел, но мы можем выбрать его сами, задав достаточно большое значение для уменьшения вероятности пропуска маленьких сдвигов или поворотов; например, 100. Льготы представляются целыми числами, поэтому 1 — это наименьшее значение (из тех, что мы можем выбрать), от- личающееся от узловой точки. Подставляя 1 и 100, мы получаем 123550 и 356200,со- ответственно. Итак, мы выбрали следующие точки НА: (1, 123550) и (100, 356200). Наш следующий шаг — выбор точки ВНЕ. Для начала выберем точку на границе, по- середине между двумя точками НА, то есть Льготы = 50. Подставляя это значение в уравнение границы, мы получаем 238700. Но наша точка ВНЕ должна лежать сна- ружи домена, в данном случае — немного выше, поэтому мы берем точку ВНЕ рав- ной (50,238700.01). Последнее, что нам надо сделать, это подставить полученные три набора значений в уравнение для налогов, чтобы подучить наш предсказанный итог. Однако будьте уверены, что вы подставляете точку ВНЕ в уравнение расчета налогов для домена 5, а не домена 4. Выполнив это, мы получаем следующие варианты теста: Льготы СОД Налог 1 123550.00 31172.0000 50 238700.01 31172.0036 100 356200.00 31172.0000 Это не является проявлением случайной корректности, поскольку наша зада- ча заключается не в поиске различий между точками в одном и том же домене, а в определении, не попала ли точка по ошибке в другой (например, смежный) домен. При расчете налога для точки ВНЕ в этом домене (4) получается 31172,0031 вмес- то 31 172,0036. Налог получился один и тот же для всех трех точек, однако домены и налоговые ставки не были линейно независимы. Вообще говоря, подобная ситу- ация нетипична, и это подтверждает следующий пример: Неравенство точка НА #1 (х. у) точка НА #2 (х. у) точка ВНЕ у >- 0 0. 0.0001 0. 10 -0.0001. 5 х >- 0 0.0001. 0 10. 0 5. -0.0001 2у < х+4 2. 3 12. 8 6.999. 5.499 4у >= х-4 4. 0 20. 4 12.0001. 1.999 у <= -х+16 0. 16 16. 0 8.0001, 8.0001 Я не стану приводить результат вычисления функции в этом домене, но давайте предположим, что он у нас есть и что случайная корректность со смежным доменом отсутствует. Я проиллюстрирую процедуру на примере проектирования тестов для последней из этих границ. Нам надо выбрать точки НА как можно дальше друг от друга, имея в виду, что, используя слабую стратегию Nx 1, мы можем проверить
лишь границу целиком и не можем проверить отдельные сегменты данного домена. Таким образом, я могу взять любые значения на прямой, и наиболее далекими друг от друга будут точки (х=0, у= 16) и (х-16, у = 0). Средняя точка между ними бу- дет равна (8,8). Поэтому для теста мы используем значения х = 8.0001 и у = 8.0001. Оси X и Y также принадлежат границам этого домена. Ошибки, связанные с коор- динатными осями, встречаются довольно редко, но вы, возможно, все-таки захоти- те их протестировать. Минимальное значение у равно нулю, поэтому (0, 0.0001) и, например, (0,10) — неплохой выбор для точек НА. Тогда для точки ВНЕ получаем значение (-0.0001, 5). Следующее уравнение описывает открытую границу, и поэ- тому мне пришлось вычесть небольшую величину, чтобы точка ВНЕ лежала внут- ри. Я надеюсь, что вы нарисуете эти линии, их закрытия и тестовые точки на мил- лиметровой бумаге, чтобы проследить за тем, что я делал. 7.4.7. Сильное тестирование доменов Отличие между сильным и слабым тестированием доменов заключается в том, что при слабом тестировании мы разрабатываем ряд тестов для каждого граничного неравенства, в то время как при сильном тестировании мы используем отдельный набор тестов для каждого сегмента границы1. Но это не означает использования той или иной стратегии. Ваше тестирование может быть слабым по отношению к одному набору границ и сильным по отношению к другому. Все зависит от ситу- ации. Используйте слабое тестирование, если для использования сильного у вас нет особых причин, подобных приведенным ниже. 1. Разрыв в граничном неравенстве. Это означает, что у вас есть три сегмента, подлежащие тестированию. Вы, разумеется, можете захотеть протестиро- вать сегмент разрыва сам по себе, однако будет лучше, если вы протестиру- ете обе части граничного неравенства по обе стороны от разрыва как нера- венства, а не как сегменты. 2. Изменение направления закрытия в одном или более сегментах — хороший повод выбрать сильную стратегию по отношению к данному неравенству. 3. Процесс обработки построен таким образом, что некоторые контрольные точки попадают в область, которая впоследствии не обрабатывается. Предположим, у нас есть несколько доменов и любой ввод, не попадающий в эти домены, от- брасывается. Программный код проходит три ступени — проверка соответс- твия данных, классификация ввода, обработка Используя слабое тестиро- вание, вы выбираете точки, которые попадают в запрещенную область. Они отбрасываются, но тестирование логики разбиения на классы — это, собствен- но, не то, что вас интересует. Два набора перекрывающихся доменов — это все, ' На самом деле мое разделение стратегий на сильные и слабые обманчиво. Подходящий набор спецификаций в случае, когда требуется «сильное» тестирование, подразумевает наличие, по мень- шей мере, одного неравенства для каждой точки, в которой меняется направление закрытия границы, и/или в начале или конце каждого разрыва границы. Если вы обладаете подобной дополнительной информацией, любое ваше тестирование будет слабым — у вас нет необходимости тестировать пере- сечение само по себе.
что у вас есть. Первый набор определяет границы принять/отбросить, а второй задает обработку. Подобная реализация в известном смысле избыточна, но та- кой подход необычайно популярен. Если вы в данном случае воспользуетесь слабой стратегией, это может ввести вас в заблуждение. Многие вводы будут отбрасываться, так как они лежат вне обрабатываемых доменов, но отбрасы- ваются они из-за случайной корректности. Выбирая здесь слабую стратегию, вы сделаете вывод о корректности границ, задающих обработку, основываясь на данных проверки границ. Это опасное заблуждение. Сильное тестирование, вероятно, будет более безопасным. Чтобы сделать обоснованный выбор, вам придется заглянуть в программный код. 4. Вникните в стиль программирования. Если я вижу ясный, четкий, управляе- мый таблицами узел обработки с точно идентифицированными граничными неравенствами, и к тому же существует универсальный модуль, выполня- ющий классификацию, то, скорее всего, в сильном тестировании нет необ- ходимости. Напротив, если для определения каждого домена реализован специальный код, программа полна сложных структур IF-THEN-ELSE, а гра- ничные предикаты избыточны, то стоит использовать сильное тестирование. Если это был старый код, который раньше рабо-ал и был сохранен, то у вас, по-видимому, нет выбора, поскольку слабое тестирование может пропустить слишком много доменов, не обнаружив ошибок в их реализации, в то время как они там есть. Если у вас есть новый код, который, однако, был реализо- ван неудачно, то я бы на вашем месте начал со слабого тестирования, так как уже оно выявит большое число ошибок. Если код был изменен в результате исправления ошибок, которые мы обнаружили при помощи слабого тести- рования, то следует продолжить слабое тестирование. Однако если бы про- граммисты сводили исправление ошибок к латанию дыр, лишь бы только это работало, я бы рекомендовал использовать сильное тестирование. 7.5. Рассмотрение приложений 7.5.1. Индикаторы приложений Тестирование доменов не годится для тестирования систем или даже программ це- ликом. Никакой одиночный метод с этим не справится. Вот некоторые характер- ные особенности приложений, для которых применимо тестирование доменов: 1. Части спецификаций, заданные непосредственно в виде численных нера- венств. 2. Сложная численная обработка с большим количеством логических условий. Например, налоговые формы, обработка платежных ведомостей, финансовые вычисления и почти все операции, выполняемые в электронных таблицах. 3. Численные вводы и сложная проверка соответствия входных данных и их классификация, даже если впоследствии отсутствует трудоемкая числен- ная обработка.
4. Не ограничивайте ваше знание тестирования доменов и его применение только программным обеспечением, Мы рассматриваем тестирование чер- ного ящика, поэтому мы делаем минимум предположений о том, что тес- тируется и как это реализовано. Тестирование доменов может быть дей- ственным методом тестирования систем, которые могут содержать или не содержать программное обеспечение (что редко встречается в наши дни). Если система, вне зависимости от того, как она реализована, описывается (отчасти) алгебраическими неравенствами, то это свидетельствует о воз- можности применения тестирования доменов. 7.5.2. Предположения об ошибках Ниже в порядке важности приведены ошибки, которые мы чаще всего рассчиты- ваем обнаружить в тестируемой системе. 1. Ошибки спецификации доменов. Неопределенные домены — специфика- ция входного пространства неполна; противоречивые домены — перекрытие доменов, особенно для границ с направлением закрытия в обе стороны; пере- определенный домен — существование домена невозможно из-за слишком большого количества неравенств; вырождение домена там, где он не нужен. 2. Ошибка границ домена. Неправильное закрытие, сдвиг, поворот, пропу- щенная граница, лишняя граница. 3. Ошибка обработки домена. Здесь рассматриваются корректно определен- ные домены, у которых, однако, обрабатывающая функция неверна. Выбор неверной функции более вероятен, чем ошибка в реализации этой функции. 4. Ошибка в узлах домена. Они проявляются только в узловых точках опре- деляемых доменов, особенно если присутствует большое количество специ- альной логики. 7.5.3. Ограничения и предостережения Применение любого метода ограничено, и тестирование доменов не исключение. Ниже приводится краткое изложение ограничений, обсуждаемых в этой главе. 1. Циклы. Мы предполагаем, что в процессе выбора доменов отсутствуют цик- лы. Циклы, включенные в процесс обработки домена, нам не опасны до тех пор, пока вы можете гарантировать, что обработка какого-либо домена не приведет к переходу программы на обработку другого домена. Существуют теоретические методы обработки циклов, которые могут влиять на границы, но они лежат за рамками данной книги. 2. Случайная корректность. Случайная корректность — это проблема для всех методов тестирования. Наиболее вероятной ситуацией является случайная корректность по отношению к отбрасываемым входным доменам. Это озна- чает, что из-за случайной корректности плохие вводы отбрасываются по не- верной причине.
3. Слепота и эпсилон. Тестирование доменов слепо к ошибкам, меньшим, чем выбранное вами е. Возможно, вам не удастся выбрать единственное значение для всего вашего тестирования. Ваша обработка может ограничивать преде- лы малых значений в вашей системе (например, 10'399), и выбор соответству- ющего е будет означать потерю значимости. 4. Сложность с выбором точки ВНЕ для закрытых доменов. Для доменов, ко- торые граничат с доменами, отбрасываемыми на вводе, точка ВНЕ ничего вам не скажет, так как проверка соответствия ввода происходит раньше, чем выбор домена. 7.5.4. Автоматизация и инструментальные средства К настоящему времени не существует коммерческих инструментов, обеспечивающих полноценное тестирование доменов. Некоторые автоматические генераторы тестов используют эвристическое одномерное тестирование доменов и затем создают ряд комбинаций значений экстремальных точек. Плюсом этого метода является то, что для применения стратегии 1x1 вам не нужны какие-то специальные инструменты, кроме калькулятора для элементарных вычислений и собственного желания. Вам не нужны алгебраические инструменты для проверки полноты и последовательности границ домена [WHIT95]. Все инструменты, необходимые для тестирования боль- ших размерностей, имеются в большом количестве в математических библиотеках [BISW87, KOLM88], Плохая новость состоит в том, что они практически не связаны друг с другом, что затрудняет их использование при тестировании доменов. 7.6. Резюме Тестирование доменов представляет собой формальный, автоматизируемый метод, призванный так или иначе заменить общепринятую, но неэффективную практику тестирования экстремальных входных значений и их комбинаций. Тестирование доменов основано на формальной процедуре определения доменов как набора входных неравенств, заданных во входном пространстве. Слабая стратегия 1x1 тестирования доменов используется для адекватных неравенств, а неадекватные тестируются при помощи сильной стратегии 1x1. Стратегии более высокого по- рядка, такие как Nx 1 и стратегии, описанные в [AFIF92], могут помочь устано- вить природу ошибок (например, сдвиг, поворот), если это является одной из ваших задач. Полная автоматизация проектирования тестов и их выполнение воз- можны при современном развитии вычислительной техники, однако поддержка этих возможностей коммерческими инструментами весьма незначительна. 7.7. Вопросы для самопроверки 1. Дайте определение следующих терминов: смежные домены, граничное урав- нение, граничное неравенство, сегмент границы, центр тяжести, законченная
граница, закрытая граница, закрытый домен, ошибка закрытия, коллинеар- ный, последовательное закрытие, вырожденная граница, вырожденный до- мен, домен, неопределенный домен, граница домена, набор границ домена, противоречивый домен, ошибка сдвига домена, ошибка поворота домена, окрестность эпсилон, внешняя точка, гиперплоскость, незаконченная гра- ница, непоследовательное закрытие, входное пространство, входная пере- менная, входной вектор, внутренняя точка, линейный домен, линейно за- висимые неравенства, линейно зависимые векторы, линейно независимые векторы, линейно независимые уравнения, линейное неравенство, нелиней- ный домен, Nx 1, точка ВНЕ, 1x1, точка НА, открытая граница, открытый домен, выходное пространство, выходная переменная, выходной вектор, па- раллельный, интерпретация предиката, область, ошибка сдвига, сильное тестирование доменов, субдомен, ошибка поворота, вектор, узловая точка, тестирование домена. 2. Что является шестым доменом в примере подраздела 7.3.1? 3. Найдите неопределенность в первой спецификации подраздела 7.3.2. 4. Найдите все огрехи в последней спецификации подраздела 7.3.3. 5. В бланке SE определяются следующие домены: протестируйте их Self_Employment income (Доход от частного предпринимательства) ЧП_доход < 433.13 433.13 <= ЧП_доход <= 57600 57600 < ЧП_доход < 135000 135000 <= Чистый ЧП_доход Тариф 0 0.153 * Чистый_ЧП_доход 0.029 * (Чистый_ЧП_дохсд -57600) + 8812.80 11057.40 6. Продемонстрируйте, что стратегия 1 х 1 работает для любой комбинации открытых и закрытых границ в одномерном пространстве. 7. Начертите границы доменов, задаваемых последними неравенствами под- раздела 7.4.6, и идентифицируйте все эти домены. Разработайте набор тес- тов, используя сильные стратегии 1 х 1 и Nx 1. 8. Для каждого из следующих примеров разработайте набор тестов, используя стратегии 1 х 1 и Nx 1. Под набором тестов подразумеваются входные значе- ния и предсказанные итоги. 1) Вычисляемая функция: и = Зхг + 1пу - ехр(х2 • у3) + 17. Неравенства: -37 <= х2 + у2 - Юх - 8у <= -25, х >= 1, у >= 0. Тесты: (х = 5, у = 8), (5, 6), (5, 2), (5, 0), (6.999, 4), (9.001, 4). Я вам дал варианты тестов, ваша задача их обосновать. 2) Вычисляемая функция: Зх + 7у - 908.7345 Неравенства: 1 <= х <= 3, 2 <= у <= 10, х2у*135 >= 30 3) Вычисляемая функция: 14х + 3.5х2 + 17 Неравенства: 0 <= 14х + 3.5х2 + 17 <= 31, 0 <- х <= 4
Синтаксическое тестирование 8.1. Обзор Синтаксическое тестирование — это мощный метод для проверки команд- но-управляемого программного обеспечения и сходных приложений. Он доста- точно легко осуществляется и поддерживается многими коммерческими инстру- ментальными средствами. 8.2. Основные термины Внешние термины: алгебра, ANSI, приложение, ASCII, булева, символ, код, ко- манда, связь, содержание, управление, база данных, накопитель, файл, имя файла, идентичность, вход, целочисленный, непосредственное соседство, язык, уровень, логическое ИЛИ, макро, модель, MS-DOS, имя, число, операционная система, вы- борочно, Pascal, конвейеризация, программа, переадресация, последовательность, набор, программное обеспечение, дерево, UNIX, значение, переменная. Внутренние термины: ошибка, чистый тест, покрытие, грязный тест, тестиро- вание доменов, связь, покрытие связей, вес связи, цикл, тестирование цикла, узел, покрытие узлов, объект, итог, путь, отношение, спецификация, тестирование ко- нечного автомата, система, тест. Алфавит. Набор определенных символов, применяемых в данной задаче. Например, ASCII, иероглифы, {а, Ь, с, х, у, %, 7}. Алфавит может меняться в за- висимости от приложения и даже отличаться для разных тестов. Не забывайте проверять алфавит, так как большое количество ошибок (найденных путем син- таксического тестирования) возникает из-за использования неверного алфавита, например, ASCII вместо ANSI.
Тире. Тире между двумя элементами алфавита заменяет собой все элементы в алфавите, начинающиеся с первого и заканчивающиеся последним элементом, в предположении что естественный порядок этих символов понятен, как, например, «а-я». «1-9» означает целочисленные символы от 1 до 9, включительно. Метасимволы (или металингвистические символы). Символы, используемые для описания языка. Используемые метасимволы включают в себя: {, }, |, [, ], (, ), *, +, <, >, ?, 0, 6, а, Ф, :, :=, =, -, (запятая), (пробел) и символы, используемые в обычных текстах. Интерпретация и применение метасимволов будут обсуждаться ниже. Мы будем рассматривать слова и команды, составленные из символов, а так- же способы их тестирования, поэтому так важно различать тестируемые символы и символы, которые описывают тестируемые символы. Для того, чтобы описать тест, включающий символ |, обычно этот символ дублируют. То есть используют комбинацию символов «| |». Так, например, «[[» означает не два метасимвола «[», а одиночную квадратную скобку, которая фигурирует в тесл е. Нуль (X). Металингвистический символ, используемый для обозначения от- сутствия символа. Не путайте X с символом пробела (о), или пустым символом (0). Символ пробела (о). Металингвистический символ, обозначающий знак пробе- ла (например, в напечатанном тексте). Пробелы между словами в предложении используются для удобства чтения и не являются частью нашего описательного языка. Пустой символ (0). Металингвистический символ, обозначающий пустоту. Он может совпадать, а может и не совпадать с символом пробела Типичное отличие между пустым символом и символом пробела заключается в том, что о создает видимое пространство при печати или в изображении чего-либо, в то время как 0 — нет. Строка. Последовательность, состоящая из ноля или более символов алфави- та. Например, авб567х000111, 1776,666999,{:{ |)>, —/Д\—• Строки идентифици- руются при помощи букв верхнего регистра, например, А. Набор строк. Наборы строк выделяются фигурными скобками, например, {А}. Набор, состоящий, к примеру, из нулевой строки X — {X), обозначается просто X. Имя строки. Другой способ обозначить строку, это заключить ее имя в угловые скобки, подобно <имя_строки>. Строковое имя также может быть именем набора строк. Например, <имя_строки_альфа>::={х,хх,ав,сде}. Команда. Строка, используемая для управления. Команды состоят из комбина- ции полей, операторов, операндов и разделителей. Командно-управляемое программное обеспечение. Программная система или ее часть, в которой основное управление происходит посредством строк, вводимых из командной строки, как, например, MS-DOS и UNIX. Командный язык. Набор команд, используемый для управления командно- управляемым программным обеспечением. Основная задача синтаксического тес- тирования — проверка командных языков. Синтаксис. Правила, определяющие, что является, а что не является правиль- ной строкой (например, командой). Правила могут быть, а могут и не быть универ- сальными для всех команд, как, например, корректная форма представления чи- сел. Но для каждой команды в командном языке должно существовать какое-либо
правило. Синтаксическое тестирование используется для проверки, сможет ли программа распознать правильным образом составленные строки и отбросить не- корректно составленные. Строковое поле, (или просто «поле», если смысл понятен из контекста) Часть строки, которой вы даете определенное имя. Операнд. Имя объекта, фигурирующего в командах: например, в команде DEL С: <имя файла>, объект <имя файла> является операндом. Операнды, как правило, имеют вид слов в обычном языке, таких как «имя файла» или «имя носителя». Оператор. Специальные символы или строки, показывающие, какое действие должно быть выполнено над определенным операндом. В предыдущем примере ключевое слово DEL является оператором. Ключевое слово. Оператор (обычно), который имеет вид обычного слова, такого как DELETE, STORE, OPEN. Несмотря на то, что ключевое слово может состоять из боль- шого числа символов, это, тем не менее, одиночный оператор. Разделитель. Символы алфавита, используемые для разделения отдельных операторов, операндов, и/или для обозначения конца команды. В качестве обще- принятых разделителей обычно используют символы £, а, (,), J (возврат каретки), = (перевод строки), [, ], /, \, «, » и ,. Грамматический разбор. Процесс разбора строки, чтобы выделить в ней поля, операторы, операнды и разделители. Программа, которая это выполняет, называ- ется синтаксический анализатор. Любые командно-управляемые системы долж- ны иметь синтаксический анализатор, но зачастую он реализуется неявно. Главной задачей синтаксического тестирования является проверка синтаксического ана- лизатора. Нам не обязательно знать конкретный способ проведения синтаксиче- ского анализа, чтобы тестировать анализатор. Синтаксический анализ. Грамматический разбор в применении к одиночному полю или части команды, например, идентификация поля подстрока как строки <число>. Синтаксическое тестирование используется для проверки корректности синтаксического анализа, выполняемого программой. Семантический анализ. Операнды имеют определенные значения. Число во введенной команде, кроме того, что оно является правильно составленной стро- кой, имеет еще и значение. У этого значения могут быть пределы, то есть макси- мум и минимум. Синтаксическое тестирование не имеет непосредственного отно- шения к семантическому анализу. Этот анализ лучше делать при помощи других методов, таких как тестирование доменов для численных полей. Интерпретация команды. Предположим, что был проведен грамматический разбор команды и семантический анализ входящих в команду полей. Затем полу- ченные данные были отправлены в программу на обработку, что означает выпол- нение команды. Акт выполнения команды называется интерпретацией команды. Лексическая эквивалентность. Если вы замените буквы английского алфави- та на равнозначные буквы, скажем, в кириллице, то вы создадите новый команд- ный язык, который будет лексически эквивалентен первоначальному. DELETE С: *.*, ДЕЛЕТЕ X: *.*, ДЕЛЕТЕ Г: *.* и ЧК’гл 3: *.* лексически эквивалентны, посколь- ку мы всего лишь заменили алфавит. Лексическая эквивалентность может озна- чать трансформацию строки из нескольких символов в единичный символ, как,
например, ПЛЮС трансформируется в +. Лексическая эквивалентность может также подразумевать изменение направления чтения слева направо на направле- ние справа налево или сверху вниз. К примеру, DELETE С: *.* может трансфор- мироваться в *.*: 3 гг’гк']. Важно понимать эту концепцию в применении к локали- зованным продуктам, чтобы избежать лишней траты сил на переделку тестов, в то время как проблема заключается в тривиальном изменении алфавита для лекси- чески эквивалентного набора команд. Если два набора команд различаются толь- ко лексически, то, как правило, вы можете автоматически конвертировать тесты, написанные для одного алфавита, в тесты, написанные для другого. Лексический анализ Операция идентификации операторов и операндов и их конвертация во внутренний язык, в котором числа, называемые маркерами, за- меняют каждый оператор и операнд. Эту операцию называют также маркировкой, поскольку в результате входная строка, составленная в определенном алфавите, конвертируется в строку маркеров. Лексический анализ, обычно явный и прос- той, должен присутствовать в любой командно-управляемой системе. Лексически эквивалентные наборы команд маркируются в один и тот же набор маркеров. Синтаксическое тестирование используется для проверки корректности лекси- ческого анализа. Нулевой набор. Набор Ф, не содержащий никакой (даже нулевой) строки. Голова строки (или начало). Первый символ строки при ее проходе слева на- право (в соответствующем алфавите с лексико-графическим упорядочением, ра- зумеется). Хвост строки (или конец). Последний символ строки при ее проходе слева направо. Конкатенация. Если А и В строки, а С — строка, полученная в результате сцеп- ления головы В с хвостом А, тогда говорят, что в результате конкатенации А и В получилась строка С. Конкатенация изображается путем непосредственного со- седства соединяемых строк, например, АВ. К примеру, если <строка_а>: :={xxxyzz], а <строка_б>: :=<111011>, тогда результат конкатенации будет выглядеть как <стро- ка_а><строка_б>={хххуггШ011}. Если {А} и {В} являются наборами строк, то {А}{В} означает конкатенацию каждой строки из {А} с каждой строкой из {В}, с сохране- нием порядка следования. Если {А}: :={111, 4, х}, а {В}: :={/, Я], то {А]{В}: :={111/, 1111. 4/, 42, х/, х£}. Если А является строкой, то для нее выполняются равенства: ХА = АХ = А. Если А — набор строк, то Х{А} = {А]Х = {А}. Или. Если А и В строки, то А | В (еще пишут А+В), читается «А или В», что означает либо строку А, либо В, либо обе сразу. Поскольку это определение вво- дится для строк, а одиночные символы можно рассматривать как строки длиной в один символ, то определение применимо так же и для одиночных символов. Или для строк аналогично логическому ИЛИ и так же подчиняется законам коммутатив- ности и ассоциативности, то есть А | В = В | А, А | (В | С) = (А | В) | С. Очевидно, А | В | С | D... и А + В + С + D... — это то же самое, что {А, В, С, D...}. Показатель степени. Если А — строка, то А" означает п повторений А. Например, если А: :=##$Х, то А2: := #$Х#$Х, а А3: : = #$Х#$Х#$Х. Согласно определению А°::= X. Краткая запись А" '” используется для обозначения ряда от п до m повторений строки: Так А3-6 = А3 [ Д'11 А51 А6. Если {А} — набор строк, то {А}'1 означает конка-
тенацию наборов {А}{А}{А}...{А} ровно п-1 раз. Так {А}2 = {А}{А}, {А}3 = {А}{А}{А} и так далее. Плюс в показателе. Если А является строкой, то Ат обозначает одно или более повторений строки А: А, АА, AAA, AAA, АААА......А”. Если А : := ху, то ху, хуху, ху- хуху... По аналогии для {А}+, где {А} — набор строк имеем: {А}, {А}{А}, {А}{А}{А}... Оператор «звезда». Если А — строка, то А’ обозначает ноль или более повторе- ний строки А: X, А, АА, ААА,... По аналогии, для {А}', где {А} — набор строк, имеем: X, {А}, {А}{А}, {А}{А}{А}. Или {А}' = {А}+1X.. Очевидно, АА' = А'А = А+. Объединение. Если {А} и {В} — наборы строк, то {А} | {В} называется объедине- нием {А} и {В}, и обозначает совокупность всех строк {А} и всех строк {В}, без пов- торений. Альтернативные обозначения: {А} + {В}, {A} U {В}. Обезглавливание. Создание новой строки путем удаления ноля или большего числа символов, начиная с головы строки. Например, строка 6567x00011 была по- лучена из строки abd567x00011 удалением первых двух символов. Укорачивание. Создание новой строки путем удаления ноля или большего чис- ла символов, начиная с хвоста строки. Например, строка abd567x000 была получе- на из строки abd567x00011 удалением последних двух символов. Подстрока. Строка А называется подстрокой строки В, если А может быть по- лучена из В обезглавливанием и/или укорачиванием В. БНФ, Форма Бэкуса-Наура [ВАСК95]. Способ задания строк, использующий введенные выше операторы и обозначения с минимальными изменениями и рас- ширением обозначений. .:=. Отдельный металингвистический символ, означающий «определяется как». Например, <имя_строки_альфа>: :=хуг<строка_бета><стрска_гамна> | <дельта>. Это можно интерпретировать как «строка с именем “имя _строки_альфа” опреде- ляется как последовательность символов х, у, z в указанном порядке, за которы- ми следует строка с именем “строка_бета”, а за ней строка с именем “строка_гам- ма” или строка с именем “дельта”». Мы считаем, что «строка бета>, <строка_гамиа> и <дельта> имеют свои собственные определения. Определение БНФ. Определение набора строк с использованием определений оператора, нуля, конкатенации, операции ИЛИ, показателя, плюса в показате- ле, оператора «звезда», нулевого набора и имени строки или имени набора строк. Определения БНФ обычно выписываются сверху вниз, однако бывает, что опре- деления приходится передвигать, чтобы определить текущие символы алфавита. Например: <нулевой_вход> <нули> «целомисленные_нули> <десятичные_нули> <тире> = А.|Р“127|а0127 | (0а | о0)1и |<нули>|<тире> = <целочисленные_нули>|<десятичные_нули> = 0-12 = Q1-12.Q0-6 = _11' Обратите внимание, что в приведенной выше спецификации (0а | а0)1-63 от- личается от (001-63 I (00)1-63. В первом случае получаем {0а, а0, 0аа0, 0а0а, а0о0, ...}, в то время как второй включает в себя только {0а, 0а0а, 0а0а0а, ..., а0, а0а0, а0а0о0}. Не пытайтесь упростить данное выражение, используя обычную алгебру. Здесь тождества обычной алгебры не работают [BRZO62],
Необязательное поле. Необязательные поля обозначают, заключая их в скобки, как, например, [«^необязательное поле >]. Очевидно, что скобки служат для ко- роткой записи показателя 0-1. То есть [«^необязательное поле >] — это то же са- мое, что и «^необязательное поле >0-1. Одиночный произвольный символ. Обозначается как «?» и означает любой оди- ночный символ алфавита. Например, выражение ????abce.xxx означает, что перед abce.xxx идут четыре произвольных символа. Произвольная последовательность символов. Обозначается как «*» и означа- ет ввод любых разрешенных символов в заменяемое им поле. Не следует путать это с оператором «звезда». Интерпретация произвольной последовательности символов зависит от контекста и не может быть предсказанной. Так, в строке DELoC:*.exe только знание операций из MS-DOS указывает нам на то, что звез- дочку * надо рассматривать в данном случае как произвольную последователь- ность символов, заключенных между двоеточием и точкой, и что эта последо- вательность должна удовлетворять некоторым правилам, установленными для строк в данной позиции (например, количество символов в строке не должно превышать 8). Произвольные последовательности символов, такие как *, которые могут обо- значать неопределенное число символов или произвольные последовательности, обозначающие множественные поля или наборы строк, потенциально опасны, и их надо избегать при проектировании тестов Они представляют опасность, по- скольку их интерпретация может меняться и зависеть от контекста. По этой же причине они перспективны для поиска ошибок 8.3. Отношения и модель 8.3.1. Основы Преобразование БНФ-спецификации в график, представляет собой механиче- ский и поэтому автоматизируемый процесс [BRZO62], Это делается с помощью многократного применения четырех преобразований: Серия (конкатенация). Сегменты БНФ, состоящие из <поле_а><поле_Ь>, моде- лируют при помощи связи, с весом <поле_а><поле_Ь>. <Г1оле_а> <Поле_Ь> Параллельное соединение (дизъюнкция). Сегменты БНФ, состоящие из <поле_а> | <поле_Ь> | <поле_с> ...<поле_п>, моделируют с помощью узла ветвления, каждая из связей которого имеет вес, равный одному из элементов (называемых дизъюнкта- ми), далее эти связи сходятся в одном в одном связывающем узле. Мы не акценти- руем внимание на узлах, изображая их окружностями в синтаксических диаграм- мах, так как эти узлы сами по себе не обладают важными для нас внутренними свойствами. Обычно мы используем вторую форму.
<Поле d> <Поле_Ь> -»•— <Поле_с>---- <Поле_п> -»— <Поле а> Показатель, начинающийся не с нуля. Показатель, такой как <поле>п-ш, ин- терпретируется как цикл, который выполняется по меньшей мере пине больше ш раз. Я сократил количество повторов цикла на 1, так как поле в цикле находится на нижней связи. Если бы я вставил это поле в верхнюю связь (эквивалентная мо- дель), то количества повторов стали бы равны соответственно пит. Это альтер- нативная допустимая модель. Оператор, обозначаемый плюсом в показателе, оп- ределяет собой цикл от единицы до бесконечности. { от п--1 до пт-1 раз —<Поле_в_ци <ле> > <Поле_в_цикле*^ от п до m раз Показатель, начинающийся от нуля. Оператор «звездочка» определяет здесь цикл от 0 до бесконечности. Есть несколько допустимых альтернативных, но эквивалент- ных моделей, обозначающих прохождение цикла 0 или большее количество раз. Они показаны на рисунке. Вспомните, что X — нулевая строка. Оператор «звезда» обозна- чает цикл от 0 до бесконечности, который можно представить также как А + |Х. Учитывая эти предварительные замечания, мы можем создать некие модели для ввода данных в различных строках формы 1040. Например, для номера соци- ального обеспечения. Поле номера социального обеспечения состоит из трех час- тей по три, два и четыре символа соответственно. Между этими полями разрешен почти любой разделитель, кроме цифр. Наша спецификация в первом приближе- нии может быть следующей: <ном_соц_обесп> <цифра> <разделит> «другие? = <цифра>3<разделит>1п<цифра>г<разделит>' л<цифра>4 - 0|1|2|3|4|5|6|7|8|9 - р|Х|сг|<другие> = а|Ь|с|...А|8|С... БНФ-форма может отличаться от этой спецификации. Вы можете ее написать с помощью различных, но эквивалентных способов. Я не указываю, сколько раз- делителей необходимо вводить, но я экспериментально определил, что в моих на- логовых документах наличие разделителя между полями вообще не обязательно. Следовательно, я пишу X в третьей строчке. Я мог бы написать вместо <разделит>*"
определение <разделит>0л, а затем не ставить X в третью строчку, так как <что-либо>°=Х. Я подразумеваю, что определение <другое> означает что-то еще. Однако вам сто- ить проверить и убедиться, что это поле включает в себя управляющие символы. Прежде чем идти дальше, убедитесь в том, что вы поняли эту спецификацию. В моем налоговом пакете, хотя, возможно, к вашему это и не относится, очень мало ограничений, относящихся к этому полю. Мне не удалось найти верхний предел разрешенного числа входных символов. Такой предел, вероятно, сущест- вует, и любое тестирование данного программного обеспечения должно это про- верять. Давайте определим верхний предел как 65 536 для каждого разделителя. Моя новая модель будет выглядеть следующим образом: <ном_соц_обесп> <цифра> <разделит> <другие> = <разделит>0'65536(<цифра><И1ае“,0'65536),(<цифра>|<разделит)* - 0|1|2|3|4[5|6|7|8|9 = ₽|Х|а|<другие> = а|Ь|с|..,А|В|С... Это не спецификация для социального номера, это описание того, что допуска- ет мой налоговый пакет. Он допускает почти все и извлекает первые девять цифр, используя их как социальный номер. Выбрав девятизначное число, он игнорирует все, что следует дальше. ВНС устанавливает более жесткие и сложные правила для корректного социального номера, так как они диктуют, где и какие цифры должны стоять, а также семантические ограничения на численные значения полей. Простая БНФ-спецификация для социального номера может иметь следующий вид: <ном_соц_обесп> <цифра> <разделит> : <цифра>3<разделит><цифра>2<разделит><цифра>4 ::= 0|1|2|3|4|5|6|7|8|9 ::= о|-|/ Теперь мы можем описать нашу модель более привычным способом. Узлы. Узлы — это точки, куда приходят входящие связи и откуда выходят исхо- дящие. Это означает, что они являются узлами слияния или ветвления (как пра- вило, и тем и другим). Узел ветвления заменяет оператор ИЛИ. Отношение (связь). Здесь мы рассматриваем отношение «соединен с». Это означает, что если А соединен с В, то между А и В на графе рисуется связь. Веса связей. Веса связей являются важной частью БНФ-спецификаций. Вес связи может представлять собой имя другой части спецификации со своим собс- твенным графом, или сам граф. Например, для первой строки в предыдущей спе- цификации весами будут <разделит> и <цифра> с соответствующими показателями. Вместо этого я могу написать следующее определение: <ном_соц_обесп> : := <цифра>3<а|-|/><цифра>2< oj-1/ ><цифра>4 Или <ном_соц_обесп> <0|1|2|3|4|5|б|7|8|9>3<о|-|/><0|1|2|3|4|5|б|7|8|9>2 <о|-|/><0|1|2|3|4|5|6|7|8|9>4 Показатели также включаются в веса циклов. Как это часто бывает с подобными моделями, в первое время вам, возможно, будет удобно чертить графы в графической форме, но когда вы освоитесь с моде- лью, необходимость в этом отпадет. Вы будете уже работать с текстовым представ- лением графа. Вы неоднократно сможете убедиться на практике, что текстовое
представление графа может представлять собой страницу для одной единствен- ной команды, в то время как эквивалентная графическая форма займет не одну страницу и будет больше путать, чем помогать. 8.3.2. Комментарий о трудозатратах Не надо путать усилия, затрачиваемые на изучение БНФ-представления, с объ- емом работы, необходимой для тестирования реального программного обеспече- ния. Иногда идею довольно просто объяснить, но ее реализация требует массы усилий. Так, например, идея Великой Китайской стены сама по себе не слишком сложна. Если вы это понимаете, то, считая, что у вас есть достаточно хорошая спе- цификация, пускай не БНФ, но уже готовая, вы, возможно, сможете обрабатывать две типичные команды за час (например, команды MS-DOS). Если вам приходит- ся подробно исследовать команды, чтобы определить все поля и ограничения в этих полях, то разбор одной команды может занять день или больше. Большинство примеров и упражнений в этой главе должны занимать у вас около часа или двух. 8.4. Методы 8.4.1. Основы Кроме тестирования вводимых команд, синтаксическое тестирование применяют для решения большого количества задач, однако тестирование команд очень хо- рошо подходит для иллюстрации данного метода. Как обычно, мы начнем с рас- смотрения спецификаций. 1. Потребуйте спецификацию команд (фактически строк), которые вы собира- етесь тестировать в наиболее формальном виде. Такая информация должна существовать, иначе что же будет реализовывать программист и каким об- разом пользователь узнает, как ему управлять программой? Если речь идет об уже существующей системе, то вы можете найти нужную информацию в справочных файлах (подобных справке о командах в системе MS-DOS) или, на худой конец, изучить командный синтаксис экспериментально. 2. Просмотрите команды на предмет поиска в них повторяющихся частей, ко- торые встречаются в большом количестве команд. Например, в MS-DOS 6.2 следующие поля используются в множестве команд: <адрес>, <устройство>, <каталог>, <имя_носителя>, <имя_файла>. <целочисленный>, «ВКЛЮЧИТЬ | ВЫКЛЮЧИТЬ>, <путь>, <время>. Это надо сделать, чтобы избежать повторяющихся специфи- каций для общих полей. Если вы дважды определяете одну и ту же сущность, то возникает вероятность что эти две спецификации не будут идентичны и, соответственно, повышается вероятность сделать ошибку в проекте теста. 3. Ищите в командах ключевые слова. В MS-DOS каждая команда имеет клю- чевое слово, но в командах встречаются и другие ключевые слова, такие как AUTO, AUX, СОМ1, COM2, COM3, COM4, CON, LPT1, LPT2, LPT3, ON, OFF, PATH, PRN. Как и в пре- дыдущем пункте, мы делаем это, чтобы избежать повторяющихся специфи- каций и, соответственно, ошибок в тесте.
4. Начните формирование ваших определений с ключевых слов, посколь- ку именно они с наибольшей вероятностью будут модифицированы при лексических изменениях (например, при переходе с английского языка на французский). Это будет простой алфавитный список. <auto> :: = AUTO | AUTo | AUtO |.... | auto <aux> ::= AUX|AUx|AuX|Aux|aUX|auX|aux <последнее_ключевое_слово> Вам, возможно, удастся сэкономить время. Вместо того чтобы выписывать все возможные комбинации букв верхнего и нижнего регистров, вам будет удобнее написать нечто вроде: <А>::=А|а, <В>::=В|Ь В таком случае спецификация для ключевого слова <аих> примет следующий вид: <aux>::=<A><U><X> Аббревиатуры команд используются во множестве систем. DELETE может быть сокращено до DEL, DELE или DELET. Тут не существует общих правил, вы должны самостоятельно решить, что в вашем случае допустимо, а что — нет. 5. Создайте БНФ-спецификацию для общих полей, таких как «носитель*. 6. Составьте список команд в порядке возрастания сложности, где сложность определяется числом полей в команде и тем, как много определений более низкого уровня вам пришлось привлечь. 7. Сгруппируйте команды. Мы не объединяем команды по принципу произво- димого ими действия. Это может быть хорошо для демонстраций при про- даже системы, но не для ее тестирования. Группируйте их в соответствии с их характеристиками, такими как использование общих ключевых слов, использование общих определений полей, похожих структур. Например, у нас могут быть команды, имеющие одну и ту же структуру. <ключевое_слово_команды* ::= «имяносителя*: «путь* «разделитель* [\<swl>] <разделитель*[\<5м2*]<возврат> Правильный выбор групп упростит проектирование тестов и само тести- рование, поможет избежать ошибок при разработке теста и сэкономит время, затрачиваемое на проектирование. 8. Для всех полей, содержание которых (например, численное, целочисленное, строковое и т. д.) может меняться, обычно существует семантическая специ- фикация (например, минимальное и максимальное значения). Определите все подобные семантические характеристики и решите, какой метод тести- рования вы будете использовать. 9. Спроектируйте тест. Для каждой команды нужен свой набор тестов — чис- тых и грязных. Каждый чистый тест будет соответствовать определенно- му пути в синтаксическом графе этой команды. Как обычно, вы выбираете
путь, активизируете его, предсказываете выход, определяете критерии со- ответствия, убеждаетесь в правильности выхода и т. д, Вы должны выполнить первые восемь шагов вне зависимости от того исполь- зуете ли вы автоматический генератор тестов, или делаете это вручную. Первые восемь пунктов в этом списке составляют от 50 до 75 процентов всей работы, за- трачиваемой на проведение синтаксического тестирования. Обратите внимание, насколько я был требователен к деталям, в частности, не пользуясь предположе- нием о взаимозаменяемости букв верхнего и нижнего регистров Не делайте по- добных допущений, поскольку операционная система, а. следовательно, и тести руемое вами приложение различают такие вещи. 8.4.2, Иерархия покрытия Покрытие узлов в данном случае вряд ли будет эффективным, поскольку узлы здесь не обладают интересными для нас свойствами. Однако покрытие связей нам будет необходимо. Так как мы имеем дело с циклами, мы также будем использо- вать тесты для циклов. 8.4.3. Чистое синтаксическое тестирование Я считаю правильным разбить синтаксическое тестирование на две части: чистое и грязное. Чистое тестирование означает обеспечение покрытия (связей) па гра- фе, плюс дополнительные тесты для циклов. Это легче показать, чем рассказать. На рис. 8.1 показана спецификация для строки «вецественное число> в языке Pascal, чья Б11Ф задается следующим образом: ^-вещественное число> : :=<цифра>+<Х| ,<цифра>+><Х|<Е1е D|d><X| + | -хцифра>+> <цифра> ::=0|1|?|3|4|5|6|7|8|9 Здесь я привожу мой тестовый набор, обеспечивающий покрытие (исключая специальные случаи для циклов): 01,2.34,5.6Е78,9.0е+1,0.CD-000, OdO. Эти шесть тестовых вариантов (и еще фактически бесконечное число эквивалентных тестов) обеспечивают полное покрытие связей. Простейший способ убедиться в этом — это прочертить заданные пути на копии этого рисунка. Рис. 8.1. Синтаксический граф для строки < веществен ное_число>
Наш следующий набор тестов направлен на проверку циклов. Вам надо про- верить каждый цикл для следующего количества итераций: 0, 1,2, типичного, max - 1, max и max +1. Мы не можем пройти цикл ноль раз, по крайней мере, в рамках чистого теста, так как это нарушило бы описанную в спецификации син- таксическую структуру. Все ли циклы были протестированы для случая 1? Если да, тогда в других тестах нет необходимости. Типичные значения различны для различных приложений, поэтому нет смысла тестировать их без знания статисти- ки. Кстати, типичные значения обычно не особо перспективны для поиска оши- бок, они нужны скорее в политических целях, чтобы убедить (без статистического подтверждения) людей в работоспособности системы. А как насчет максимальных и близких к ним значений? В операторах + и * скрыто прямое приглашение поискать ошибки. В компьютере все числа конечны, а значит, должны быть и максимальные значения. Например, в реально существу- ющей спецификации оговаривается, что ни одна команда или оператор не могут состоять более чем из 255 символов. Вы должны найти правило, вне зависимости от того, скрытое оно или явное, и спроектировать тесты для этих случаев. Давайте предположим, что у нас есть следующее простое правило: <вещественное_число>: :=<цифра>1;,)<Х.| .<un$])a>112><X.|<E|eD|d><X| + | - ><цифра>13> Эта спецификация может быть проверена для случаев max - 1 и мах при помо- щи следующих тестов: 123456789.12345678901el2, 1234567890.123456789012е123. Почему я комбинирую по три значения max - 1 и max б отдельных тестах? Не луч- ше ли будет отказаться от комбинации значений для трех полей и проверить цикл по каждому полю отдельно? Стоит задать себе вопрос, какие ошибки вы ожидаете здесь встретить. Вы ожидаете встретить ошибку такую, что программа будет рабо- тать, если два из трех ее полей превышают свои допустимые значения, и не будет работать, если все три поля меньше этих пределов. Мне кажется, что это не слиш- ком похоже на естественную ошибку. Какие типы ошибок мы ищем, когда проверяем операторы + и *? Было время, когда работа программного обеспечения могла нарушиться всего лишь из-за непра- вильной реализации предельных значений. Однако вероятность встретить подоб- ную ошибку в современном программном обеспечении невелика. Программисты знают об этой проблеме и стараются ее избегать. Чаще всего ошибка возникает, если у двух или более программистов существуют различные нотации макси- мальной величины. Один программист берет предел равным 512, другой 65 536, а третий вообще считает, что 20 вполне достаточно. Ожидаемая в данном случае ошибка возникает вследствие несогласованности в нотациях вычислительно бес- конечных циклов. Например, программист ограничил ввод 65 536 цифрами. В бо- лее поздней программе, обрабатывающей это число, разрешено не более 20 цифр и некорректно предполагается, что предыдущая программа тоже ограничивает свой ввод 20 цифрами. 8.4.4. Грязное синтаксическое тестирование Используя грязное синтаксическое тестирование, мы решаем одновременно две задачи: пытаемся нарушить работу программного обеспечения, подбирая подхо-
дящий пример отдельных синтаксических ошибок для всех команд, и добиваемся вызова всех диагностических сообщений, связанных с этой командой. Если мы хо- рошо справились с первым заданием, то есть шанс, что и второе задание тоже ока- жется выполненным, однако в любом случае это неплохо бы проверить. Давайте сначала закончим тестирование циклов. Мы должны рассмотреть слу- чай нулевого числа итераций для каждого цикла. Вот некоторые из моих тестов: .05, 1., 1.1е. В случае грязного теста, я беру значения max+ 1 равными: 12345678901.1, 1.1234567890123,1.1 е 1234. Обратите внимание, что в грязных тестах я делаю толь- ко по одной ошибке, а для всех остальных полей выбираются самые простые зна- чения. К этому моменту чистые тесты должны быть уже пройдены, поэтому про- грамма должна читать и интерпретировать все символы при условии отсутствия ошибок. Для грязных тестов ситуация иная, поскольку если, например, первое поле содержит слишком много или слишком мало цифр, то число отбрасывается и ошибочный код для второго поля уже не будет выполняться. Я хочу убедиться, что вне зависимости от способа реализации весь код будет протестирован. Если при тестировании возникает более одной сшибки, то какой бы ни была ошибка, обнаруженная первой, она инициирует запрет исполнения текущей команды, и последующий (возможно ошибочный) код нс будет протестирован. Поскольку мы не можем сказать, не глядя в код программы, какое поле будет обрабатываться в первую очередь, наиболее безопасно иметь только одну ошибку в каждом поле. Существуют и другие, более веские причины иметь одновременно не более одной ошибки при проведении грязного тестирования, но их я буду обсуждать позже. Грязное синтаксическое тестирование достаточно простой метод. Надо всего лишь соблюдать нескольких простых правил: Каждая БНФ-спецификация пред- ставляет собой дерево (на самом деле — порожденный подграф). Выполняя тес- тирование, мы начинаем с вершины и заканчиваем листьями — реальными сим- волами. Дерево поделено на уровни. На вершине дерева (например, дерева «веществен- ное число-*) мы имеем несколько синтаксических элементов, определенных непо- средственно, а также другие элементы, которые заданы в спецификациях на более низких уровнях дерева. Мы вносим какую-либо одну ошибку в определенное поле или откладываем определение ошибки этого поля на более низкий уровень. Мы продумываем ошибки для каждого уровня так, чтобы иметь одновременно только одну ошибку в одном поле. В каждое поле мы можем внести ошибку сразу или от- ложить ее внесение на более низкий уровень. Вносимые нами ошибки делятся на синтаксические или семантические. Ниже приведена БНФ-спецификация (упрощенная для ясности) для коман- ды COPY в MS-DOS 6.2. Оригинал фактически полностью идентичен предложен- ной БНФ-спецификации, за исключением небольших различий в обозначениях. Я не стал рассматривать некоторые усложняющие моменты, такие как ограни- чение общей длины команды, различные ограничения, накладываемые на длину строки <путь>, допустимые и обязательные типы и положения разделителей меж- ду полями и переключателями /А и /В. Я разрабатывал спецификацию последова- тельно сверху вниз, по одному уровню за раз, именно так, как я собираюсь стро- ить тесты.
Level 1: <сору> = COPY a [/YI/-YK+ «источник*)1'" [а <конечндя_цель>][/\/] L2: L2: «источник* «конечная_цель* L3: «иня_носителя* L3: «путь* L3: «иня_файла* L4: «имя_кат* L4: «расш* L5: «кат_буквы> L5: «ф_буквы* = [«имя_носителя>:] [«путь*][«имя_файла>] = [«имя_носителя>:] [«путь*][«имя_файла>1 - a|b|...z|A|B|...Z = (\<имя_кат *)‘“\ = «ф_буквы*1в[.«расш*] = «кат_буквы>1'6[ .«расш*] = «ф-буквы*1'3 = «а|b|c - z| А|В|С - Z|0|l|2 - 9 | А | $ | - I 1 I #1 « I -1 {{ I }} I «|))> : := «кат_буквы>| « @ | 'Г > Несколько слов об уровнях. Поле «расш* возникло на уровне 4, поскольку именно столько определений мне пришлось ввести, для того чтобы дать это опре- деление. Но в то же время это поле фигурирует в определении «инякат*, из чего следует, что его определение должно даваться на уровне 5 Какой из этих двух ва- риантов правильный? Оба. Дело в том, что это дерево определений представля- ет собой частично упорядоченную структуру, в то время как понятие «уровень» — строго упорядочено и неприменимо к частично упорядоченным графам, таким как наше дерево определений. Вы можете возразить, что появление одного поля в двух различных местах и в различных контекстах может стать причиной ошиб- ки из-за различия в обработке этих двух случаев. Все правильно. В хорошем про- граммном обеспечении такая вероятност ь мала, и поэтому не стоит беспокоить- ся по поводу одного или двух пропущенных случаев. Если же вы имеете дело с настоящей халтурой, тогда действительно это может быть хорошим тестом. При проверке недоброкачественного программного обеспечения необходимо большее число тестов для достижения полного покрытия, но оно ломается при любом сис- тематическом тестировании. В первом поле находится ключевое слово COPY Если бы это была моя первая тестируемая команда, то я бы должен был начать с работы над этим ключевым словом. Все команды в MS-DOS начинаются с ключевых слов. Если распознава- ние ключевых слов не действует, то вряд ли какие-либо другие команды будут ра- ботать. Существует вероятность, что такое тестирование в этом проекте уже про- водилось. Какие ошибки стоит внести в ключевое слово, если мы собираемся его проверить? 1. Оставить поле пустым. 2. Написать почти правильно, пропустив один символ, например, СОР. 3. Написать слишком длинно, например COPYME. 4. Взять правильное ключевое слово, но не относящееся к этой команде, на- пример, СОМР. Подобные ошибки вряд ли встретятся в хорошем программном обеспечении, но для недоброкачественного программного обеспечения имеет смысл попробо- вать проверить пункты 2 и 3. Оставшаяся часть команды должна быть свободна от ошибок, поэтому в итоге получаем следующие тесты: Т1.1.1: СОР а а:*.* и Т1.1.2: COPYME о а:*.*.
Несколько комментариев относительно этих двух тестов. Вы, должно быть, за- метили, что я выбрал самый простой вариант, исключив максимально возмож- ное число последующих полей. Это само но себе уменьшает вероятность отмены выполнения этой команды по какой-либо другой причине. Я также использовал оператор произвольной последовательности символов (*), поскольку подозреваю, что обработка произвольной последовательности символов является характер- ной чертой, общей для многих команд, и что она, возможно, использует область с путем, отличным от пути для обработки данной команды. Если я хочу избежать использования произвольной последовательности символов на этой стадии тес- тирования, то мне придется использовать нечто вроде иня файлаЛз! и иметь в рас- поряжении подобный файл, который можно будет скопировать. Теперь рассмот- рим следующее поле — разделитель. В сущности, условия при которых вам нужен или нс нужен разделитель (в на- шем случае а), могут быть довольно запутанными, и моя модель это не отражает. Вам не нужен разделитель, если в качестве следующего символа используется обратная косая черта, применяющаяся для переключения. Вообще существу- ют несколько типов разделителей. Давайте не будем столь пунктуальны и пред- положим, что используется только а и что он обязателен, как показано в мо- дели. Мы получаем два следующих варианта теста: Tl.2.1: COPY а:*.* и Т1.2.2: COPY 00 а:*.* Первый тест отвергается, как и должно быть, однако второй проходит глад- ко. В чем дело? Либо спецификация, либо модель неверна. Неверна наша модель (БНФ вариант спецификации): в ней должно быть о14, где q обозначает макси- мально допустимое число разделителей, равное общему числу символов в коман- де минус 127, то есть 118. Значит, по всей видимости нам надо проверить это при помощи грязных и чистых тестов: q = 0, грязный; Т 1.2.1; q = 1, чистый; q= 117, чис- тый; q = 118, чистый; q = 119, грязный. Разберемся теперь с полем переключателя. Вот несколько вариантов: невер- ный переключатель в этой позиции, слишком много переключений, неверны оба переключателя. Эти варианты приводят к следующему набору тестов, каждый из которых должен определить наличие ошибки. Т1.3.1. COPY /0 А:*.* Tl.3.2. COPY //Y а А:*.* Tl.3.3. COPY /V 0 А:*.* Tl.3.4. COPY /Y/-Y О А:*.* Т1.3.5. COPY /Y/V О А:*.* Т1.3.6. COPY /Y/Y/V О А:*.* Выполняя эти тесты, я обнаружил, что не следую должным образом своей соб- ственной модели. Корректная спецификация отличается от приведенной. Я до- бавлял знак + к каждому источнику, хотя он нужен только в тех случаях, когда у нас больше одного источника. Следовательно, более корректная спецификация будет выглядеть следующим образом. <сору> ::=COPY а1" [Л|/^]<источник>(+<источник>)°',‘ [а<конечная_цель>][/У] Какие ошибки мы можем внести в поле <источник>? Для начала обратите вни- мание, что поля файлов для двух источников связаны. Должен быть, как минимум,
один источник. Поскольку в конечную цель также входит имя файла, программа не сможет правильно обработать команду, если мы опустим имя файла источника, а взамен используем имя файла конечной цели. Поэтому нам придется опустить их оба в нашем грязном тесте. Тогда у нас есть следующие варианты: нет источ- ника (и нет конечной цели), слишком много источников, синтаксическая ошибка в источнике, семантическая ошибка в источнике, изменение положений знака +. Tl.4.1. COPY Tl.4.2. COPY oA:filel.txt file2.txt Tl.4.3. COPY aA:fjlel.txt ++file2.txt Tl.4.4. COPY oA:a+b+c+d+e+f+g+h+i+...+aa... (больше максимального предела числа источников, п) Т1.4.5. = Т2.1. Синтаксическая ошибка в спецификации источника Т1.4.6. = Т2.2. Семантическая ошибка в спецификации источника В Т1.4.4 я использовал очень короткие имена файлов без расширений, посколь- ку я хочу превысить максимально допустимое число исходных файлов в этой ко- манде. Мне пришлось создать большое количество файлов с именами, состоящи- ми из одного символа, затем с именами из двух символов и так далее. Выполняя этот тест, вам следует убедиться, что вы не превысили максимальную длину стро- ки — 127 символов. Тесты 1.4.5 и 1.4.6 фактически являются тестами следующего уровня. Я ис- пользовал систематическую схему нумерации тестов. Первая цифра обознача- ет уровень, вторая — тестируемое поле, а третья — способ внесения ошибки в это поле. Пропуск поля или использование слишком большого числа полей — это тес- ты первого уровня. Однако синтаксические и семантические ошибки в этих полях тестируются на следующем уровне. На этом уровне также были проделаны грязные тесты для поля конечной цели и его разделителей, так как спецификации для источника и конечной цели практи- чески полностью совпадают. Единственное, что мы можем сделать — протестиро- вать синтаксические и семантические ошибки в спецификации целевого файла: Tl.5.1 = Т2.3. Синтаксическая ошибка в спецификации целевого файла 11.5.2. = Т2.4. Семантическая ошибка в спецификации целевого файла Последний полезный тест, который мы можем сделать на этом уровне — пора- ботать с переключателями, преимущественно тем же способом, который мы ис- пользовали для первого переключателя. Т1.6.1. COPY oA:file.txt/ Tl.6.2. COPY oA:file.txt aV Tl.6.3. COPY 0A:file.txt// Tl.6.4 COPY oA:file.txt/V/V Tl.6.5. COPY <jA:file.txt/Y Аналогичной последовательности надо придерживаться и для следующего уровня исследуемого нами дерева. Семантические ошибки в поле источника озна- чают синтаксически корректное имя файла для несуществующего файла. Поле ис- точника на самом деле более сложно, чем показано в нашей модели. В него должно входить хотя бы одно поле с правильным именем. Это означает, что носитель и/ или путь и/или файл должны быть определены. Следовательно, более корректная спецификация будет выглядеть следующим образом:
(«имя носителя»:[«путь»][«имя файла»])|([«имя носителя»:]«путь» [«имя файла»])|([«имя носителя»:][<путь»]<имя файла» Если у вас есть один из двух компонентов, то два других не обязательны. В то же время в спецификации целевого файла все поля не обязательны. Ошибки второго уровня — это синтаксические и семантические ошибки в полях источника и целево- го файла. Из-за того, что поля не обязательны, на этих уровнях встречается не так уж много синтаксических ошибок. Это означает, что нам достаточно иметь один из трех компонентов для источника. По всей видимости, единственное, что мы можем сде- лать на этом уровне, — поэкспериментировать с двоеточием, использовать неверный символ (;), ввести слишком много полей или вообще не указывать их. За исключени- ем семантических ошибок (отсутствие такого источника и отсутствие такого целево- го файла), все остальные тесты мы можем сделать на следующем уровне. На уровне 3 мы экспериментируем с «имя носителя», «путо> и «имя файла». Число носителей, допустимое в MS-DOS, и, следовательно, семантика и синтаксис име- ни носителя зависят от версии MS-DOS. Поскольку поле «путь» не является обя- зательным, то единственные ошибки, которые мы можем сделать на этом уровне, это пропустить требуемый символ обратной наклонной черты в конце строки пути или ввести их слишком много. Неверный путь семантически рассматривается на следующем уровне. Я мог бы попробовать имя файла с точкой, но без расширения. На четвертом уровне тестируются семантические и синтаксические ошибки в содержимом или в структуре имен каталогов и расширений. Здесь используется тот же набор, что и раньше. Пропустите какие либо обязательные элементы, вве- дите их слишком много, введите вместо них другой, неверный элемент, сделайте семантическую ошибку. Продолжайте в таком же духе, пока не дойдете до листьев дерева, то есть до того места, где вы вводите реальные символы. Я твердо придерживался правила делать не больше одной ошибки за раз. Для этого у меня есть две причины, и обе они важны. 1. Слишком много тестов. Проверка команды MS-DOS COPY потребовала при- близительно 75-100 тестов и потребовала бы гораздо больше, если бы в ос- нове нашего тестирования лежала реальная БНФ-спецификация со всеми своими переключателями и другими сложностями. Вне зависимости от чис- ла тестов, проводимых вами для единичной ошибки, для двойной ошибки количество требуемых тестов придется возвести в квадрат. Коммерческие инструментальные средства [ IDEI94, POST94] проделывают все это, если только у вас есть БНФ-спецификация или ее эквивалент. Эти инструмен- ты генерируют чудовищное число грязных тестов. Для типичной системы, имеющей несколько сотен команд пользователя и оператора, вы можете с легкостью создавать около 100 000 тестов за день. Даже для автоматиче- ского выполнения это достаточно большое число. Для двойных ошибок это цифра вырастет до 10 000 000 000, а для тройных? 2. Потеря ошибок. Оказывается, что теоретически невозможно создать ге- нератор грязных тестов, который гарантированно генерирует только грязные тесты. Специфика синтаксиса приведет к предположительно грязным тестам, которые будут легко проходиться. Система «пройдет»
подобный тест, и вам придется проводить расследование. Если возни- кает слишком много ложных сигналов тревоги, то даже при наличии ав- томатизации польза, приносимая данным методом, сходит на нет. Если вы рассматриваете двойные ошибки, то возникает вероятность потери ошибок. Например, в выражении (x + y + (z-w) пропущена правая скоб- ка. Если я делаю две ошибки, чтобы получить либо x + y + (z-w), либо (х + у + z — w), мы имеем в итоге две синтаксически корректные строки — ошибки были потеряны. Скобки и другие парные разделители (BEGIN-END, DO-ENDO, IF-ENDIF, PARDO-ENDPAR) могут служить простыми примерами воз- можности потерь ошибок. При проверке множественных ошибок стреми- тельно растет число тестов, однако процентное соотношение ложных сиг- налов тревоги растет еще быстрее. 8.4.5. Предсказание итога Предсказание итога для чистых тестов зависит от тестируемой команды и семан- тики. Тут не существует общих правил, и вам придется придумать их самим. Для грязных тестов предсказание итога выглядит очень просто: КОМАНДА ОТВЕРГНУТА. 8.4.6. Хорошие и плохие разновидности тестирования Некоторые разновидности синтаксического тестирования могут облегчить вам работу, а некоторые могут, наоборот, существенно усложнить. Есть однако, и дру- гая сторона медали. Программы, представляющие скверные разновидности, как правило, содержат наибольшее число ошибок, и, значит, синтаксическое тестиро- вание в этом случае весьма перспективно. 1. Формальная структура. Некоторые командные языки, такие как в UNIX, имеют формальную структуру. Вместо сотен специальных команд язык име- ет относительно небольшое число командных сегментов, компонуя которые при соблюдении специальных правил, можно добиться желаемого эффекта. С другой стороны, операционные системы наподобие MS-DOS, которые не обладают такой формальной структурой в полной мере, тем не менее, облада- ют некоторыми ее аспектами, например, возможностью конвейеризации и пе- реадресации. Для командных языков, имеющих явную формальную структу- ру, обычно бывает достаточно проверить сегменты и правила их компоновки, вместо того чтобы проверять все множество возможных команд. Это особен- но важно для грязного синтаксического тестирования, которое, как прави- ло, не слишком продуктивно при проверке командных языков с формальной структурой. Если язык программирования обладает формальной структу- рой, то обычно не представляет труда найти полную, детальную специфика- цию для всех команд, зачастую составленную в метаязыке, эквивалентном БНФ. Поэтому хотя тесты легко проектируются, они не слишком эффектив- ны. Чистое тестирование требует, разумеется, гораздо меньших затрат. Командные языки, не обладающие формальной структурой или со струк- турой, возникшей в процессе сращивания, как правило, являются хороши-
ми объектами для грязного синтаксического тестирования (и часто полны ошибок). Наиболее печально известный пример языка такого типа — это dBASE-11/III/IV — язык программирования баз данных для PC. Макроко- мандные языки для PC часто также обладают этими неприятными особен- ностями. Специализированные языки, часто «проектируемые» без должного понимания, что за язык на самом деле строится, как правило, трудны для ис- следований, поскольку документация на команды в этих языках (и особенно на хитроумные исключения) крайне скудна. Отсутствие структуры делает затруднительным автоматизацию разработки теста, и автоматический гене- ратор грязных тестов выдает много неверных тестовых вариантов. Несом- ненным плюсом таких систем, содержащих командные языки с отсутствием структуры, является простота, с которой они ломаются. 2. Точная лексическая спецификация. Существуют командные языки с точной лексической спецификацией. Ключевые слова в них четко определены и не могут соответствовать, скажем, опциям внутри команд или строкам других команд, для которых они могут показаться естественными. Спецификация языка определяет четкие правила, касающиеся преобразований алфавита и ключевых слов. Чем более ясным и логичным будет разделение между лексическими и синтаксическими аспектами, тем меньше вам придется тес- тировать. Полная проверка языка при помощи единого набора всеобъем- лющих тестов для какой-либо одной лексической трансформации дает уве- ренность в надежности других лексических эквивалентов. В то же время, если существует четкая лексическая спецификация, то не составляет труда конвертировать набор чистых и грязных тестов из одной спецификации в другую. Как я уже неоднократно убеждался, качественные программы со- держат меньше ошибок и их существенно легче тестировать. Полной противоположностью чистой лексической спецификации явля- ются языки, в которых лексические и синтаксические аспекты безнадежно перепутаны. Но хотя разработка тестов для них сложна и приходится при- кладывать много усилий для исследований, их тестирование, тем не менее, приносит результаты. 3. Синтаксис, зависящий от контекста. В хороших командных языках сущест- вует четкое разделение между синтаксисом и семантикой. В плохих языках эти аспекты безнадежно перемешаны. В качестве примера рассмотрим сле- дующую спецификацию: «команда» «разделитель!» «разделитель?» <поле2> <поле2> ::= <ключевое_слово»«разделитель1»«поле1»«разделитель2»<поле2» . .= ЕСЛИ «клкнеъое_слово» = <кл»чевое_слово_список_!» ::= X ЕСЛИ <ключевое_слово> = <ключевое_слово_список_2> :.= \|/|,|о|-| ЕСЛИ <поле1> = «поле1_синтаксис_1» X ИНАЧЕ ::= <поле2_синтаксис_1> ЕСЛИ <поле1> = “Г’ ::= «поле2_синтаксис_2» ЕСЛИ <лоле!> = "2" :.= <поле2_синтаксис_99> ЕСЛИ <поле1> = "99"
Командные языки с синтаксисом, зависящим от контекста, обычно не столь четкие и структурированные, как в только что приведенном примере. Основ- ные проблемы с этими спецификациями заключаются в том, что синтаксис какого-либо поля зависит от семантики другого поля. Дело усложняется еще и тем, что синтаксис определенного поля команды может зависеть от специфи- ческой синтаксической формы и/или от значений (семантики), приведенных в последующих полях. Лучшее, что можно сделать с такими языками, — это похо- ронить их. Их почти невозможно использовать, невозможно поддерживать, на них очень трудно программировать, но их очень легко сломать. Как правило, в таких языках код, реализующий синтаксический анализатор, полностью скрыт и так же непоследователен, как и сам язык. Перед тестировщиками подобного мусора стоит задача убедить разработчиков, что необходимо внести изменения в этот язык. Так как исследования специфических хитросплетений — сложная задача, то нет смысла за нее браться. Такую халтуру настолько легко сломать, что вы сможете легко сделать это вручную Это один из немногих случаев, ког- да тестирование заставляет меня чувствовать вину за насилие над слабым, по- добно тому, что должен чувствовать взрослый, обижающий ребенка или ма- ленькую беззащитную зверюшку. 8.5. Рассмотрение приложений 8.5.1. Индикаторы приложений Командные языки, для которых синтаксическое тестирование эффективно, явля- ются неотъемлемой функциональной частью большинства приложений. 1. Командно-управляемое программное обеспечение. Это наиболее очевидное приложение, и, по всей видимости, именно в него командные языки вклю- чаются чаще всего. Если система преимущественно командно-управляемая, то почти вся проверка может быть организована при помощи синтаксичес- кого тестирования. Я считаю полезным использование синтаксического тестирования в подобных случаях. 2. Программное обеспечение, управляемое при помощи меню. Широко рас- пространенная альтернатива командно-управляемому программному обес- печению — это программное обеспечение, управляемое при помощи меню, в котором действия выполняются путем выбора определенных пунктов меню. Наиболее подходящий метод для тестирования программ, управляемых по- добным образом, — это тестирование конечного автомата, рассматриваемое в главе 9. Вне зависимости, управляется программа при помощи меню или нет, всегда существуют поля с данными, и у этих полей есть определенный синтаксис, для проверки которого синтаксическое тестирование является вполне эффективным способом проверки. Делается это очень просто, по- скольку дерево синтаксиса, как правило, небольшое. 3. Макроязыки. Множество коммерческих программных пакетов для PC име- ет встроенный макроязык, называемый также языком сценариев. Он пред- ставляет собой язык программирования, который может использоваться
для автоматизации повторяющихся операций. В качестве примеров мож- но привести командный язык пакетной обработки в MS-DOS, оболочку Norton Desktop для языка сценариев Windows, макроязыки Lotus 123 и WordPerfect, язык сценариев CrossTalk для CASL-IV. Эти языки часто реа- лизуются в коммерческих пакетах не только для удобства пользователей, но и потому, что с их помощью удобнее всего реализовать множество сложных функций, таких как составление стандартных писем в текстовом редакторе. В идеале они являются полнофункциональными, хотя и специализирован- ными языками программирования, имеющими формальные спецификации (зачастую эквиваленты БНФ). Некоммерческие, или узкоспециализиро- ванные1 продукты, тоже весьма часто используют макроязыки, но, как пра- вило, они не столь явно определены или реализованы в виде коммерческо- го (горизонтального) пакета. Подобные языки, если они являются частью приложения, обязательно должны пройти синтаксическое тестирование. 4. Связь. Все системы связи имеют встроенный язык программирования. Это язык, описывающий формат посланий. Вы можете не догадываться о суще- ствовании подобного языка, например, в телефонии, но он есть. Телефонные коммутаторы используют особый язык для связи друг с другом. Кроме того, соответствующие локальные, междугородние и международные номера те- лефона имеют сильно формализованный синтаксис, называемый планом номера. Любое послание, использующееся для связи, должно иметь формат (то есть синтаксис), который должен быть проанализирован. 5. Язык запросов базы данных. Любая база данных имеет командный язык, используемый для того, чтобы определить, что надо искать и что надо из нее извлечь. Самые простые языки предлагают только один ключевой пара- метр. В более совершенных системах существует поиск с использованием булевой алгебры, основанный на определяемых пользователем параметрах, которые мы интерпретируем как предикаты. Подобные предикаты, очевид- но, обладают формальными синтаксисом и семантикой, и, следовательно, должны быть проверены с помощью синтаксического тестирования. 6. Компиляторы и генерируемые синтаксические анализаторы. Существует один тип продуктов, в котором не стоит использовать синтаксическое тес- тирование и особенно грязное синтаксическое тестирование. Это современ- ные компиляторы. Это может показаться странным и неверным, но это со- ответствует моей установке, гласящей, что тестировщик никогда не должен повторять тесты, выполненные ранее другими. Современные компиляторы, разумеется, имеют синтаксические анализаторы. Но эти синтаксические анализаторы генерируются полностью автоматически, с использованием генератора синтаксического анализатора, которому задается формальное описание, наподобие БНФ. Лексические анализаторы также генерируются ' Программы, предназначенные для широкого круга пользователей, такие как текстовые редакто- ры, электронные таблицы и базы данных, называются горизонтальными пакетами. Пакеты, специали- зированные для какого-то одного рода деятельности и обеспечивающие большинство необходимых для этой деятельности функций (например, для туристических агентов, цветоводов или аптекарей), называются вертикальными пакетами.
автоматически на основе формальных спецификаций. Наиболее известные инструменты для этих целей — это LEX и YACC [MASO90], Несмотря на то, что первое время они в большинстве случаев использовались исключи- тельно для генерации лексических и синтаксических анализаторов в ком- пиляторах, сейчас они и им подобные программы все чаше используются для генерации лексических и синтаксических анализаторов в командных языках программного обеспечения. Это очень хорошо, поскольку генери- руемые лексические и синтаксические анализаторы необычайно надежны. С точки зрения тестировщика применение синтаксического тестирования здесь неперспективно, поскольку даже полностью автоматизированное, оно не сможет сломать подобные лексические и синтаксические анализаторы. Прежде чем потратить массу времени и сил на синтаксическое тестирова- ние (даже автоматизированное), оцените, что это за приложение и как оно реализовано. Если в нем используется или проектируется генератор лекси- ческого и синтаксического анализатора, то вероятность успешного приме- нения синтаксического тестирования у вас довольно мала. Такие ошибки здесь не проходят. Единственное, что тут остается проверить, — это семан- тику, что, как вы видели, часто делается другими методами, такими как тес- тирование доменов. 8.5.2. Предположения об ошибках Предположения об ошибках в синтаксическом тестировании удобнее всего фор- мулировать для абстрактного синтаксического анализатора, вне зависимости от того, явный он или скрытый. Ниже приведены примеры. 1. Неполный синтаксис. Разумные с точки зрения выполняемое™ команды не принимаются, а если и принимаются, то выполняются неверно, так как син- таксический анализатор не может обработать подобную строку. Вследствие этого интерпретация команд происходит бессистемно, как правило, невер- но и ведет к сбоям, или потере данных. 2. Непоследовательный синтаксис. Синтаксис, сильно зависящий от контекс- та, ведущий к непредсказуемому и непоследовательному синтаксическому анализу, и, как следствие, к ошибкам в интерпретации. 3. Ошибочное отклонение и ошибочное принятие. Ошибки в синтаксическом анализаторе, ведущие к отклонению корректных с точки зрения выполняе- мое™ команд и принятию команд, содержащих синтаксические ошибки. 4. Синтаксическое/семантическое несоответствие. Ошибки в синтаксичес- ком анализаторе, ведущие к отклонению или некорректной модификации значений полей. Например, целые числа от 0 до 999 должны приниматься, однако реализация требует наличия ведущего ноля, в результате чего от- клоняются хорошие числа, такие как 7 и 19. 5. Лексические ошибки и ошибки в алфавите. Некорректные лексические преобразования, ведущие, скажем, к интерпретации содержания полей как
разделителей. Например, строки должны пометаться в кавычки, но не пред- усмотрена возможность обработки строк, содержащих кавычки, или пере- вод строки интерпретируется как конец поля, но невозможно ввести текст, включающий перевод строки. 8.5.3. Ограничения и предостережения При проведении синтаксического тестирования мы сталкиваемся с двумя серь- езными проблемами: психологической и методологической. Так как автомати- зация проектирования достаточно проста, то после описания синтаксиса в БНФ число автоматически генерируемых тестов может измеряться сотням и тысячами. Однако в случае генерации синтаксических анализаторов эффективность таких тестов не превышает эффективность перебора всех итераций при проверке цикла. Методологический аспект заключается в существовании мнения (ничем не оправ- данного) об эффективности того, что я называю игрой в «Эрудита» на клавиату- ре, Рахманинов-тестированием или обезьяньим тестированием. Оно представляет собой беспорядочный ввод с клавиатуры предположительно произвольных строк, до тех пор пока что-либо не сломается — этот миф обычно дополняется наличи- ем хитрого хакера, барабанящего по кнопкам. Ранее программное обеспечение для PC, а также большинство любительских программ действительно могло быть сло- мано при таком тестировании, но для современного профессионального програм много обеспечения такие случаи — редкость. Тем не менее, миф об эффективности деятельности хитрого хакера, творящего темные дела за клавиатурой, жив в обще- ственном сознании и в сознании людей, несведущих в технике тестирования. Мне встречались менеджеры по разработке программного обеспечения, искренне веря- щие, что обезьянье тестирование — это единственное тестирование, необходимое продукту. Но что такое синтаксическое тестирование, если не полностью форма- лизованное, научное обезьянье тестирование9 В таком случае большим заблужде- нием будет считать, что синтаксическое тестирование недостаточно надежно. 8.5.4. Автоматизация и инструментальные средства Возможно, наиболее привлекательная сторона синтаксического тестирования — это простота, с которой разработка теста может быть полностью автоматизиро- вана. Возможно, из-за простоты автоматизации этот метод поддерживают ком- мерческие инструменты, такие как (Т) [IDEI94, POST94]. И даже в отсутствие коммерческих инструментов проектирование языка тестов, воспринимающего БНФ-спецификацию, соответствующего интерпретатора тестового языка и гене- ратора чистых/грязных тестов не является сложной задачей. Вы определяете свой метаязык, как если бы он был обычным языком, и затем используете лексический анализатор и генератор синтаксического анализатора, наподобие LEX или YACC, чтобы они сделали ббльшую часть работы. Разумеется, вы проверяете и сам свой генератор, используя его для генерации тестов. У меня есть несколько неплохих генераторов, построенных для себя. Разработка каждого из них заняла триместр у одного хорошего (но не гениального) студента, проходящего курс обучения языку программирования, который включал в себя изучение LEX иYACC.
Я оцениваю скорее нижний предел требуемых трудозатрат, поскольку во мно- жестве приложений работа с коммерческими инструментами, такими как Т, ус- ложняется тем, что вам необходимо принимать в расчет специальные входные интерфейсы, автоматизацию выполнения теста, специфику платформ и тому по- добные вещи. Это особенно характерно для случаев, когда входные данные не вво- дятся с клавиатуры обычным способом (например, при передаче телекоммуника- ционных сигналов), а должны быть интегрированы глубоко внутрь приложения. 8.6. Резюме Синтаксическое тестирование представляет собой мощное, легко автоматизируе- мое средство, предназначенное для тестирования лексических и синтаксических анализаторов командного процессора в командно-управляемых приложениях. Синтаксическое тестирование начинается с определения синтаксиса путем зада- ния формального метаязыка, среди которых наиболее популярен БНФ. После за- дания БНФ непосредственной задачей тестировщика является генерация набо- ра тестов, полностью покрывающих синтаксический граф. Стандартное покрытие связей мы обычно дополняем чистыми и грязными тестами для проверки показа- телей, особенно операторов + и *. 8.7. Вопросы для самопроверки 1. Дайте определение следующих терминов: алфавит, ассоциативный, обез- главливание, пустой символ, БНФ, команда, командно-управляемоепрограмм ное обеспечение, командный язык, коммутативный, конкатенация, синтак- сис, зависящий от контекста, укорачивание, тире, разделитель, дизъюнк- ция, потеря ошибок, показатель (метасимвол), генерируемый синтаксичес- кий анализатор, ключевое слово, LF.X, лексический анализатор, лексическая эквивалентность, связи (в синтаксических графах), макроязык, программное обеспечение, управляемое через меню, метаязык, метасимвол, узел (в синтак- сических графах), нулевой символ, нулевой набор, операнд, необязательное поле (обозначение в БНФ), парные разделители, параллельное преобразова- ние, синтаксический анализатор, грамматический разбор, плюс (показатель) оператор, семантический анализ, серия преобразований, язык сценариев, символ пробела, оператор «звезда» (метасимвол), строка, поле строки, голо- ва строки, имя строки, набор строк, хвост строки, подстрока, синтаксический анализ, синтаксис, маркер, маркировка, оператор объединения, произвольная последовательность символов, произвольный символ (одиночный), YACC. 2. Поэкспериментируйте с вашим налоговым пакетом и определите опытным путем БНФ спецификацию для следующих полей в форме 1040. После того как вы это сделаете, разработайте набор чистых и грязных тестов, обеспечи- вающих следующее покрытие. Окончание налогового года, имя, отчество и фамилия, полный адрес, за исключением почтового индекса, почтовый ин-
деке плюс маршрут доставки, поле 6с, число месяцев, которое иждивенец жил дома, поле даты в области для подписи. 3. Поэкспериментируйте с вашим налоговым пакетом и определите опытным путем БНФ спецификацию для поля социального обеспечения. Мой на- логовый пакет очень нестрогий и позволяет широко варьировать синтак- сис. Однако что впоследствии интерпретируется как входные данные — это отдельный вопрос. Определите синтаксис для приемлемых вводов и спро- ектируйте для них тесты. Затем определите полную БНФ-спецификацию, которая в том числе включает информацию о том, как должны преобразо- вываться различные строки для того, чтобы извлечь из них нужные числа, если это возможно. Спроектируйте чистые и грязные тесты. 4. Определите БНФ-спецификацию для целочисленных входных данных, со- стоящих из одной или двух цифр. Используйте только положительные чис- ла. Включите сюда различные символы, которыми люди могут естественно заменять ноль или отсутствие вводов, например, пустой, нулевой символы, О, о, -, -0- и т. д. Затем спроектируйте набор покрывающих чистых тестов и хорошие грязные тесты для единичной ошибки. 5. Определите БНФ-спецификацию для суммы в долларах, включающую по- ложительные и отрицательные вводы, пустые, нулевые вводы, с центами и без, с запятыми и без, и так далее, для всех способов, которыми люди мо- гут ввести подобные данные в налоговую декларацию. Затем спроектируй- те чистые тесты, обеспечивающие покрытие, и грязные тесты для единич- ной ошибки. 6. Определите части команд <устройствс>, <гуть>, <иня_файла> в MS-DOS, или эквивалентные им в вашей операционной системе. Затем спроектируйте полный набор чистых и грязных синтаксических тестов. 7. Исследуйтеследующиекоманды MS-DOS (или аналогичные команды ввашей операционной системе) и задайте для каждой полную БНФ-спецификацию, включающую поля <устройство>, <путь> и <имя_файла>, которые вы можете счи- тать ранее протестированными. Затем спроектируйте покрывающий набор чистых и грязных синтаксических тестов. Предусмотрите возможность ис- пользования аббревиатур, псевдонимов и различных алфавитов. Проверьте только ваши грязные тесты, испытав их. (Замечание: если вы случайно разра- ботали чистый тест, то с последствиями его выполнения для вашей системы вы будете разбираться сами.) Команды: APPEND, ATTRIB, BUFFERS, CHOIR, COMMAND, COPY, COUNTRY, DATE, DIR, EXPAND, FC, FORMAT, KEYB, PRINT, SHARE, SORT, TIME, XCOPY. 8. Спроектируйте тесты синтаксического анализатора для старой английской валюты. Вам дается произвольное число денежных единиц, каждая из кото- рых состоит из числа и следующего за ним символа этой единицы, например: «ЗЕ, 17s, 8р, 7S, 4hc». Синтаксический анализатор нужен для автоматическо- го размена монет. Программа должна конвертировать входные значения и выражать сумму в терминах f, h, d, s и £. Монетная система: 2 фартинга (f) = полпенса (h), 2 полпенса = 1 пенс (d), 12 d = 1 шиллинг (s), 1 флорин (F) -
2s, полкроны (he) = 2s6d, крона (с) = 5s, 20s = 1 фунт стерлингов (£), 21s = 1 гинея (G), 1 соверен (S) = 2£ 18s. Нет ничего удивительного в том, что они представляются в десятичном виде. 9. Благородному Публию Юлию Лентулу, Трибуну, всаднику, командиру XXIII легиона Привет вам, Публий: Возникли вопросы для обсуждения вашей налоговой декларации за прошлый год: 1) Вы не включили XLIV талантов серебра, которые вы получили, казнив Рубидия в прошлом году. 2) Вам позволено объявлять иждивенцами всех воинов XXIII легиона, но вы не можете поступать так ни с MMCCCIX рабами ваших воинов, ни с MMMXLIV маркитантами, так как они уже фигурируют в налоговых де- кларациях ваших воинов... Бедный Публий. Проблемы с налогами, возможно, возникали уже в те времена. Определите БНФ-спецификацию для положительных целых чисел в рим- ской системе счисления. Обратите внимание: Подчеркивание1 буквы — X, L, С, D и М — означает умножение их на 1000: например, X = 10 000, L “ 50 000, и так далее. Предусмотрите возможность использования букв верхнего и нижнего регистров. Включите все целые числа от 0 до 5 000 000. Затем проведите ряд тестов, обеспечивающих покрытие, а также грязные тесты. И помните, что главное — полнота, а не компактность. 1 На самом деле в римской системе счисления использовалось перечеркивание, но, откровенно говоря, это очень неудобно делать в текстовом редакторе. Я надеюсь, что приверженцы классической истории на меня не обидятся.
Тестирование систем с конечным числом состояний 9.1. Обзор Изначально предназначенная для тестирования аппаратной логики, модель ав- томата с конечным числом состояний (конечного автомата) является превос- ходной моделью для проверки приложений, управляемых через меню. Она важна еще и потому, что получила широкое распространение для разработки объектно-ориентированных продуктов. 9.2. Основные термины Внешние термины: приложение, поведение, начальная загрузка, ошибка, сим- вол, закрыть файл, управление, данные, проектирование, аппаратное обеспечение, файл, функциональная клавиша, целочисленный, загрузка, логика, интеграция высокого уровня (ИВУ), меню, строка меню, отображение, память, сообщение, метод, мышь, щелчок мыши, MS-DOS, объектно-ориентированное программное обеспечение, открыть файл, операционная система, последовательный порт, про- граммное обеспечение, подпрограмма, символьный отладчик, Windows. Внутренние термины: поведенческое тестирование, случайная корректность, домен, тестирование домена, граф, ввод, связь, покрытие связей, список связей, вес связи, модель, узел, покрытие узлов, вес узла, пустой, вывод, путь, состояние, сильно связанные, синтаксическое тестирование, система, значение. Состояние. Состояния изображаются узлами.
Имя состояния Входное событие. Отдельное воспроизводимое событие или фиксированная последовательность определенных событий, характеризуемых вводами (или по- следовательностью вводов) в систему. Что конкретно означает данное событие, зависит от приложения. При рассмотрении модели с конечным числом состояний я буду использовать термин «вход» для обозначения «входного события», если при этом не будет возникать двусмысленности. В качестве примеров подобных входов можно упомянуть внешний входной сигнал, входное сообщение, символ, выбор меню, определенная последовательность команд пользователя. Входы в моделях с конечным числом состояний используются скорее для управления, чем для ввода данных, то есть входы скорее вносят изменения в пове- дение системы, чем являются исходными данными для различных выводов. Это положение иллюстрируют значение целочисленного управляющего параметра, входные данные, значения которых определяют путь обработки в программе, ре- презентативный ввод для каждого входного домена. Все приведенные примеры являются отдельными входными событиями. Входное кодирование. Каждому событию может быть присвоено определенное имя или число. Это означает, что входные события могут отображаться, например, на множество целых чисел или на множество символов. Поведение системы с ко- нечным числом состояний не меняется при изменении входного кодирования. Входные символы. Набор отдельных имен или значений для входного кодиро- вания. Число входных символов. Входное кодирование задается целыми числами от 1 до, скажем, п для каждого отдельного входного события Мы полагаем, что эти числа идут подряд, без пропусков. В большинстве моделей число входных симво- лов мало — как правило, меньше 20. Большее число тоже может быть обработано, но не без помощи специальных инструментов. Код состояния. Состояния можно пронумеровать. Это называется кодиро- ванием состояния. Состояния означают выполнение определенных операций. Например, у накопителя на гибких магнитных дисках могут быть следующие со- стояния: (1) запуск, (2) включение мотора, (3) поиск дорожки, (4) поиск сектора, (5) чтение (6) стирание, (7) выключение мотора. Мы можем обозначать эти состо- яния эквивалентными им номерами, например, закодировать состояния числами от 1 до 8. Поведение системы с конечным числом состояний не меняется при из- менении способа кодирования состояний. Текущее состояние. В любой момент времени система находится в определен- ном состоянии — в текущем. Начальное состояние. Особое состояние системы обычно называется на- чальным состоянием, если оно предшествует получению какого-либо входа. Тестирование системы, не обладающей начальным состоянием, также возможно, однако это не рассматривается в данной книге. Счетчик состояний. Гипотетический или реальный адрес ячейки памяти, со- держащий код текущего состояния. Счетчик состояний часто бывает неявным.
Программный счетчик в компьютере является примером явного счетчика со- стояний. Число состояний. Счетчик состояний ограничен своим максимальным значе- нием. Если код состояний задает непрерывный диапазон, то это максимальное значение равно числу состояний. Как и в случае входных символов, число состо- яний в модели обычно невелико (меньше 30). Большее число может быть обрабо- тано при помощи специальных инструментов. Автомат с конечным числом состояний (конечный автомат). Абстрактный ав- томат (например, программа, логическая схема, трансмиссия в автомобиле) для которого число состояний и число входных символов конечно и фиксировано. Автомат с конечным числом состояний состоит из состояний (узлов), переходов (связей), входов (весов связей) и выходов (весов связей). Автоматы с конечным числом состояний в данной книге изображаются графами состояний. Переходы. Система реагирует на входные события, что может привести к смене состояния. Это называется переходом между состояниями, или просто переходом. Система передает сообщение другой системе. Во время передачи она находится в состоянии «передача». После завершения передачи она ожидает уведомления об успешном приеме данных. В этом случае она находится в состоянии «ожидание уведомления». Изменение состояния можно рассматривать как изменение зна- чения счетчика состояний. Переходы на графе обозначаются связями. Если вход X инициирует переход из состояния А в состояние В, то для обозначения этого факта мы рисуем связь от А к В с весом X. В диаграмме вход X должен иницииро- вать переход из состояния А в состояние В Переход в себя. Обозначает сохранение состояния. Изображается связью, вы- ходящей из состояния и входящей в него же. Такому переходу может соответство- вать определенный выход. Кодирование выхода. Переходу может соответствовать выход. Это означает, что в результате изменения состояния инициируется выходное действие. Выходные действия также могут быть пронумерованы целыми числами. Такая нумерация называется кодированием выхода. Поведение системы с конечным числом состоя- ний не зависит от способа кодирования выхода. Выходное событие. В результате изменения состояния система может выдавать что-либо на выход. Это эквивалентно подаче на выход целого числа, выходного кода. Если бы мы говорили о программном обеспечении (хоть это и не обязатель- но), то мы могли бы сказать, что подаче на выход числа 7, например, соответс- твует запуск седьмой подпрограммы или передача сообщения седьмому методу объектно-ориентированной программы. Выходные события также обозначаются весами связей, причем в обозначении они следуют за символом наклонной черты. На предыдущем рисунке вход X порождает выход Y. Обратите внимание, что в мо- дели на следующем рисунке оба входа вызывают изменение состояния (возможен переход в то же самое состояние, в данном случае «просмотр ТВ») и инициируют
выход (возможно, пустой, в данном случае «пропустить» для входа «кошка вош- ла в комнату»). Кошка вошла в комнату / пропустить Пустой выход. Абстрактное пустое выходное событие. Например, событие «оставить все как есть». Доступное состояние. Состояние В доступно из состояния А, если существует такой набор входов, что модель, находясь изначально в состоянии А, в итоге при- дет в состояние В. Это означает, что в графе состояний существует путь от А к В. Недоступное состояние. Состояние недоступно из других состояний, особенно из начального состояния, если оно не является доступным. Недоступные состоя- ния обычно означают наличие ошибки. Сильно связанные состояния. На практике болынинст во состояний в автоматах с конечным числом состояний являются жестко связанными при условии отсут- ствия ошибок. Изолированные состояния. Набор состояний, недоступных из начального со- стояния. Внутри этого набора изолированных состояний состояния могут быть, а могут и не быть сильно связанными. Их изолировала именно недоступность из начального состояния. Изолированные состояния в моделях тестирования про- граммного обеспечения вызывают подозрения и могут содержать ошибки. Сброс. Особый вход, приводящей к возврату системы в начальное состояние из любого другого состояния. Если любое состояние доступно из начального со- стояния и если существует сброс, то граф состояний сильно связан. Сброс не яв- ляется обязательным требованием, однако его наличие существенно упрощает проектирование теста и тестирование. Сброс также может быть реализован как возврат к особому состоянию, не являющемуся на самом деле начальным состо- янием в модели. Набор начальных состояний. Набор состояний, обладающий следующими свойствами. Он включает в себя начальное состояние (начальные состояния). Набор начальных состояний может быть, а может и не быть сильно связанным. Если был совершен переход из состояния в этом наборе в состояние, не входя- щее в этот набор, то возврат в набор начальных состояний становится невозможен. Рассмотрим начальную загрузку системы. Программное обеспечение при загруз- ке проходит ряд шагов, каждый из которых может быть интерпретирован как со- стояние. После загрузки программы возврат в набор начальных состояний невоз- можен, поскольку вы не можете «выгрузить» программу. Загрузка системы может идти с применением нескольких наборов начальных состояний. Например, каж- дый набор начальных состояний включает в себя только одно состояние и пред-
ставляет собой ступени загрузки. Тем не менее, в продуманном программном обеспечении должен быть способ возврата в начальное состояние: в операцион- ной системе Windows это комбинация CTRL-ALT-DEL. Рабочее состояние. Рано или поздно система пройдет начальное состояние и перейдет в сильно связанный набор рабочих состояний — область, в которой вы- полняется ббльшая часть тестирования. Начальное состояние в рабочем наборе. В рабочий набор может входить со- стояние, которое называется «начальное состояние». Оно не является истин- ным начальным состоянием модели, но выполняет его функции. Например, меню, которое появляется после загрузки Windows, — эго не истинное начальное состо- яние. Истинными являются состояния, входящие в последовательность загрузки. Однако с точки зрения выполнения операций в этой системе мы можем назвать это состояние исходным, до тех пор пока речь идет о тестировании меню. Подход, в котором ясно определяются различные наборы состояний и состояния, служа- щие начальными в этих наборах, представляется достаточно удобным. Набор выходных состояний. Модель может иметь одно или два состояния, или целый набор состояний, таких, что после перехода в них возврат в набор рабо- чих состояний становиться невозможен. Внутри этого набора выходных состоя- ний состояния могут быть, а могут и не быть строго связанными. Типичный при- мер — последовательность шагов при выходе из программы. Полностью определенный автомат. Автомат с конечным числом состояний на- зывается полностью определенным тогда и только тогда, когда для любой комби- нации входного кода и кода состояний задан переход (возможно, назад, в то же самое состояние) и выход (возможно, пустой). Не содержащие ошибок автоматы с конечным числом состояний полностью определены. Автоматы же с ошибками могут быть, а могут и не быть полностью определены. Программное обеспечение, управляемое при помощи меню. Программное обес- печение или разновидность программной операции, в которой основное управле- ние осуществляется выбором соответствующих пунктов в меню. Обход из начального состояния (или просто обход, если не возникает двусмыс- ленности). Последовательность переходов из состояния А (например, начально- го состояния) в состояние В и назад в А. Если в модели есть набор начальных состояний, то подразумевается обход из состояния в этом наборе, которое проек- тировалось как начальное. Данный термин также используется для обозначения
обхода набора рабочих состояний, который стартует из начального состояния этого набора. 9.3. Отношения и модель 9.3.1. Основы Материал, излагаемый в этом разделе, рассматривался и в [BARN72, BRZO63, CHOW78, CHOW88, MCNA60, MILL75], Я просмотрел множество форм ВНС и инструкций в поисках примеров систем с конечным числом состояний, которые могут быть полезны для нас, но не смог найти ничего, за исключением одного, но зато вечного состояния тревоги, кото- рую испытывает каждый из нас при упоминании о налоговой декларации. Мне придется использовать в качестве иллюстраций менее формальные примеры. Узлы. Узлы обозначают состояния. На рисунке приведено меню для програм- мы, управляемой с его помощью. Если выбран какой-то определенный пункт меню, то это означает, что мы находимся в соответствующем состоянии. Я настро- ил оболочку своей операционной системы таким образом, чтобы иметь на экране следующие пункты меню: Выход, Файл, Диск, Дерево, Вид, Настройка, Панели инстру- ментов, Окно, Загрузить DOS, Справка. МОЙ СОБСТВЕННЫЙ ПЛАН РАБОЧЕГО СТС ЛА Выход Файл Диск Дерево Вид Настройка Инструменты Qkho Загрузить QOS = Ctrl + D Справка Найти I |формат| Метка [копировать| Поиск I Запись конфиг. DOS На самом деле здесь 12, а не 10 состояний, поскольку я не включил сюда началь- ное состояние, то есть состояние, в котором ни один пункт меню не выбран. Я также не включил сюда выбор самой левой кнопки с чертой, управляющей меню. Связи. Связи обозначают переходы. В данном примере существует возможность перейти из начального состояния в любое другое состояние, если выполнить соот- ветствующее входное действие. Также возможно перейти из большинства осталь- ных 10 состояний обратно в начальное состояние (активное меню закрывается) путем нажатия клавиши ESC или ALT. Мы остаемся в начальном состоянии, если ничего не делаем, или нажимаем на любые другие (не ESC или ALT) клавиши. Веса связей (входные коды). В операционной системе Windows предусмотрен большой выбор возможностей для входного кодирования. Вот некоторые способы активизации меню, что означает смену состояния (появляется новое меню). Вьрсод файл Дерево Вид Настройка Инструменты Qkho Загрузить DOS = Ctrl + D Справка Найти Форматировать... Колировать| | Поиск | Запись конфиг | DOS |Упорядочить|Редактор|настройка| Справка 1 Метка диска... WordPerfect - [ГЛАВА 9-ТЕСТИРОВАНИЕ КОНЕЧНОГО ЧИСЛА СОСТОЯНИЙ] Вставить Схема Инструменты График Таблица Окно Справка Закрыть | Выбор при помощи мыши. Поместите курсор мыши на соответствующую об- ласть в строке меню и нажмите на левую кнопку.
Другие указатели. Кроме мыши, можно использовать и другие устройства ука- зания, такие как трекбол, джойстик, сенсорный экран, световое перо — все можно пересчитать по пальцам. Комбинация ALT+Клавиша. Если вы находитесь в начальном состоянии, то можно использовать комбинацию ALT + Ключевая клавиша, где «Ключевая клави- ша» — это подчеркнутая буква в названии меню, например, Вид. Функциональные клавиши. Функциональные клавиши могут быть запрограм- мированы для открытия определенных меню. К примеру, F1 обычно открывает меню Справка. Стрелки. Если в строке меню выбрано какое-нибудь меню, то вы можете перей- ти в соседнее меню путем нажатия на клавишу со стрелкой влево или вправо. Перечисленные выше способы представляют собой различные варианты вход- ного кодирования. Преобразование действий пользователя (нажатия клавиш или передвижения курсора мыши) во входной код часто осуществляется операцион- ной системой. Если это применимо к вашему случаю, то можете не обращать на это внимания, если вы только не тестируете операционную систему. Однако если ко- дирование выполняет ваше приложение, то вам следовало бы его проверить. Если ваше приложение поддерживает несколько входных устройств и программа обра- батывает эти устройства напрямую, то необходимо рассматривать отдельную ко- дировку для каждого такого устройства и эти кодировки должны быть проверены. В приведенном примере существует начальное состояние: состояние, в кото- ром в строке меню не выбрано ни одного меню. Для возврата в начальное состоя- ние из большинства меню существует несколько способов, например нажатие на клавишу FSC или ALT. Для большинства состояний существует переход самого в себя. В начальном состоянии нажатие фактически любой обычной клавиши приводит к переходу об- ратно в начальное состояние. Однако обратите внимание, что когда вы находитесь в одном из открытых пунктов меню, некоторые из обычных клавиш становятся активными. Например, в моем меню Справка активны следующие подчеркнутые клавиши: Быстрая справка, Содержание, Поиск по справке, Как пользоваться справ- кой, Файлы Readme, Q программе. Другие буквенные клавиши вызывают переход состояния в себя, тот же эффект производит комбинация CTRL, SHIFT и обычных клавиш. Большая их часть сигнализирует, что они «не реагируют» на нажатие. Большинство клавиш действительно реагирует на нажатие, но некоторые не де- лают этого, что означает, что была выбрана другая кодировка выхода. Такие вещи имеет смысл проверять. Веса связей (выходные кодировки). В этом примере производимые действия достаточно сложны. Предположим, в системе открыто меню или другое окно. Выбор какого-либо пункта может привести к целой последовательности дейс- твий. Некоторые из них работают в текущем окне, а некоторые открывают допол- нительные окна. Попробуем использовать эту концепцию в модели космического корабля Enterprise. У него есть импульсный двигатель с тремя возможными режимами: разгон (Р), нейтральное положение (П), задний ход (3). Корабль, в свою очередь, тоже имеет три состояния: движение вперед (В), остановка (О), движение назад
(Н). Комбинации режима работы ракетного двигателя и состояния движения ко- рабля образуют девять состояний: РВ, РО, РН, ПВ, ПО, ПН, ЗВ, 30 и ЗН. Согласно требованиям, предъявляемым к управлению импульсным ракет- ным двигателем, для того чтобы переключиться в положение «разгон» или «за- дний ход», вам надо пройти нейтральное положение. В нейтральном положении все двигатели выключены: Р<>П<>3. Допустимы следующие входы: р>р, з>з, п>п, р>п, п>р, п>з и з>п. Давайте теперь построим диаграмму состояний для корабля Enterprise. Наш корабль подчиняется ньютоновскому закону движения. Мы на- чнем с комбинации ПО, двигатели выключены и корабль стоит на месте. Если мы не будем касаться ручек управления (п>п), то ничего не произойдет и мы останем- ся в том же самом положении. Мы можем выбрать один из двух оставшихся вари- антов: разгон вперед (п>р) или разгон назад (п> з). Между моментом времени, ког- да мы повернули ручку управления ракетным двигателем, и моментом, когда этот двигатель заработает, есть некая задержка. Если мы выбрали опцию разгон впе- ред (п>р), мы перешли в состояние РО (разгон - остановка). Аналогично если мы выберем опцию разгон назад, мы перейдем в состояние 30. В любом случае, если мы будем держать двигатель включенным (р > □), то эн рано или поздно заработает и мы начнем двигаться вперед. Это переведет нас в состояние РВ (разгон - дви- жение вперед). Если мы были в состоянии РО (разгон - остановка) и при этом выключили двигатель, то вернемся обратно в состояние ПО (нейтральное поло- жение - остановка). Из рассмотрения верхних переходов ЗВ > 30 > ЗН и нижних переходов РН > РО > РВ следует, что если мы движемся в определенном направле- нии, то мы физически не можем изменить направление движения без остановки в какой-либо точке. НАЗАД < ДВИЖЕНИЕ > ВПЕРЕД Ниже приведены некоторые наблюдения, касающиеся модели и соответству- ющего ей графа. 1. Граф сильно связан, поскольку между любыми двумя состояниями сущест- вует по меньшей мере один путь. Обратите внимание на то, что эти пути не являются прямыми переходами, мы не можем перейти из одного состояния в другое, просто изменив направление движения на обратное. Например, чтобы перейти из состояния РВ в состояние ЗН, вам придется пройти следу- ющий путь: РВ-ПВ-ЗВ-ЗО-ЗН, а для перехода из ЗН в РВ: ЗН-ПН-РН-РО-РВ.
2. Моей задачей было моделирование двух факторов: управления режимом ракетного двигателя и направления движения корабля. Так как для каждо- го из них было три возможных варианта, то, комбинируя их, мы получили девять состояний. Число состояний равно произведению числа вариантов для каждого фактора. Графы состояний растут очень быстро. 3. Между входами и состояниями существует отношение. Несмотря на то, что допустимы семь входных действий, в определенном состоянии не все они разрешены. Более детальная модель (см. таблицу состояний в разделе 9.3.3 ниже) включает в себя все входы, в том числе не разрешенные. Зачем? Так как в нашем случае мы не знаем, насколько надежна система, возможно, она содержит ошибки. Предположим, например, что управление двигателем сломано и существует возможность перевода его из режима Задний ход в ре- жим Разгон, минуя Нейтральное положение (см. проблему 2). В простейшей мо- дели состояния и входы не зависят друг от друга, но это почти никогда не встречается на практике. Например, действия различных клавиш в модели меню явно зависят от состояния (от того, какое меню активно). 4. Модель космического корабля имеет совершенную симметрию, нечас- то встречающуюся на практике. Обычно переходы соединяют состояния в системе беспорядочно. 9.3.2. Модели Мили и модели Мура Модели с конечным числом состояний, используемые в этой книге, называются моделями Мили [MEAL55]. В моделях Мили выходы ассоциируются с перехода- ми. Модель, альтернативная этой, называется моделью Мура [MOOR56], и в ней выходы ассоциируются с состояниями. Модель Мура можно легко получить из модели Мили, заменив каждый код выхода, ассоциированный с переходами, на соответствующее выходное состояние, Выходные состояния обычно выделяются жирной границей или двойной границей. На рисунке я заменил переход допол- нительным состоянием, выходным состоянием, в котором происходит выходное действие. Обратите внимание на то, что мне также пришлось добавить фиктив- ный выход (пустой), чтобы показать, что переход в следующее состояние про- изойдет без дополнительного внешнего входа. Вход X / выход Y Причины, по которым я предпочитаю модели Мили: 1. Они содержат меньше состояний и, следовательно, проще сами по себе. Сложность модели определяется путем умножения числа входных симво- лов на число состояний. При увеличении числа состояний вы увеличиваете размер модели и усложняете ее тестирование.
2. Состояния в них стабильны. Модель Мура всегда содержит изменяющиеся состояния, которые не будут терпеливо дожидаться, пока мы их проверим. Это усложняет тестирование. В модели Мили вы не меняете состояния в от- сутствие входа. Справедливости ради надо отметить, что модель Мили так- же может содержать изменяющиеся состояния, если мы допускаем пустой вход, но в модели Мили обычно таких состояний меньше. 3. Они ближе к конечной реализации. Программисты, реализуя системы с ко- нечным числом состояний, обычно делают это на основе моделей Мили, а не моделей Мура. Различия тестовой и проектной моделей являются источ- ником ошибок при разработке тестов. 4. Они обеспечивают повторяемость выхода. Определенный выход (напри- мер, Открыть Файл) может соответствовать множеству различных переходов. Это могло бы потребовать отдельного состояния для каждого случая и, сле- довательно, привело бы к увеличению размера модели. 5. Их таблица представления проще. Представление модели с конечным числом состояний в виде таблицы проще для моделей Мили, чем для моделей Мура. Эти две модели теоретически эквивалентны. Каждой модели Мура соответ- ствует модель Мили и наоборот. Зачем тогда нужны эти разговоры? Согласно моим наблюдениям, в случаях, когда модели с конечным числом состояний использу- ются в проектировании, например, при объектно-ориентированном подходе, чаще используют модель Мура, а не Мили. Вы не должны смешивать два типа моделей. Выберите один из них (я настоятельно рекомендую Мили) и придерживайтесь его. Читатели, знакомые с графико-теоретическими моделями, обратят внимание на то, что я отдаю предпочтение моделям со взвешенными связями, а не моделям со взвешенными узлами. Модель Мура, разумеется, относится к последним, если рассматривать выходы. Модель Мура имеет определенные преимущества при описании последовательно переключающихся схем, особенно асинхронных. Обе модели были изначально созданы в рамках теории переключающихся схем и тео- рии автоматов. Однако мы имеем дело с программным обеспечением, а не с после- довательно переключающимися схемами. В большинстве случаев доказательства теорем проще проводить для моделей со взвешенными узлами, чем со взвешенными связями, и этим объясняется пре- валирование первых в научных работах. Тем не менее, когда дело доходит до по- строения реальных инструментов, в которых графы представляются в виде списка связей, или при использовании алгоритма сокращения числа узлов (см. [BEIZ90]), модели с взвешенными связями имеют неоспоримые преимущества. 9.3.3. Таблицы переходов Графическая форма представления моделей полезна скорее для обучения, а не как рабочий инструмент. Вы можете использовать представление в виде списка свя- зей, так же как и для любого другого графа, и, разумеется, мы часто видим по- добное представление моделей с конечным числом состояний в проектных доку- ментах. Альтернатива этому — использование табличного представления. В этом
случае мы могли бы начертить таблицу n х п (где п — это число состояний) и в каж- дую ячейку записать соответствующую ей комбинацию вход/выход. Могли бы, но не станем этого делать, поскольку такая таблица (для большей части программно- го обеспечения) будет почти целиком пуста. Вместо этого мы используем таблицу состояний-переходов, или коротко таблицу состояний. В таблице состояний каждому состоянию соответствует одна строка, а каждо- му входу один столбец. Фактически мы можем начертить две таблицы с одинако- вой разбивкой: таблицу состояний-переходов и таблицу выходов. В ячейку пер- вой таблицы мы записываем СЛЕДУЮЩЕЕ СОСТОЯНИЕ. Во вторую таблицу мы заносим соответствующий код выхода (если он есть) для данного перехода. Иногда бывает удобно комбинировать эти две таблицы, записывая и следующее состояние и вы- ходные данные в одну и ту же ячейку, например, в виде следующее состояние/код вы- Таблица 9,1. Таблица состояний корабля Enterprise Состояние 3>3 3>П п>п П>3 п>р р>р р>п 3>Р р>з ЗН ЗН пн 30 ЗН по ЗВ 30 пв пн пн ЗН РН по по 30 РО пв пв ЗВ РВ РН РО пн РО РВ ЛО РВ РВ пв Я оставил пустыми ячейки, содержащие запрещенные комбинации (состоя- ние — вход). Они невозможны в корректно реализованной системе. В данном при- мере некоторые переходы запрещены в соответствии с законами физики. Другие входы, такие как з>р и р>з запрещены из-за технических ограничений, наклады- ваемых оборудованием — системой управления двигателем. Рассмотрите, однако, вопросы 2, 3 и 4 в конце этой главы. В этом примере я не задал выходы. Какие выходы могли бы быть в модели корабля Enterprise? Наверное, запуск топливного насоса и зажигание. Различие между разгоном вперед и задним ходом могло бы заключаться в том, какой из топ- ливных клапанов (носовой или кормовой) открыт. Топливный насос и зажигание должны активироваться для обоих направлений двигателя. Поэтому несколько выходных функций могут соответствовать множеству различных переходов. При тестировании состояний мы основное внимание уделяем проверке состояний и переходов, а потом уж выходам. В менее фантастическом примере модели меню мы можем закрывать и открывать файлы во множестве различных пунктов меню. Безусловно, мы должны проверить открытие и закрытие файла. Но если файл от- крывается, как и должен, и мы в этом убедились, то у нас нет необходимости про- водить тестирование открытия файла для всех случаев (то есть всех переходов), когда это открытие может случиться.
9.3.4. Вложенные автоматы Обсуждаемая выше таблица достаточно сложна: она имеет 81 ячейку (девять со- стояний и девять входов). Пример меню на рабочем столе еще более сложен. Я на- считал 12 пунктов в строке меню и выбрал те пункты, которые могут быть активи- рованы нажатием на обычную клавишу — 23 пункта для 26-буквенного алфавита и плюс еще девять цифр, всего — 32 входных кода. Для представления этого в виде од- ной таблицы нам нужна таблица 12*32 = 382 ячейки. Мы могли бы построить такую большую таблицу, но мы не станем этого делать. На это есть несколько причин. 1. Слишком много входов. Слишком много возможностей для ошибки при проектировании тестов. 2. Слишком много пустых ячеек. Еще больше возможностей для ошибки. 3. Слишком много запрещенных комбинаций состояние/вход. 4. Есть лучший способ. Под лучшим способом я подразумеваю вложенные автоматы. Это то, что боль- шинство людей делает интуитивно. Меню панели управления Windows включает в себя три пункта: Панель управления, Настройки и Справка. Мы можем построить автомат с четырьмя состояниями: по одному состоянию для каждого из трех пунк- тов меню и еще одно состояние, соответствующее случаю, когда ни одно меню не активно. Мы строим модель этого уровня, исследуем все способы переключения .между меню, активации и деактивации меню и так далее, но ничего не делаем и не выбираем в рассматриваемых меню. Далее для каждого из трех меню мы строим отдельную модель с конечным числом состояний, которая описывает то, как дан- ное меню работает и какие опции в нем можно выбирать. То же относится к выбо- ру значка в начальном состоянии (ни одно меню не открыто) базовой модели. Продолжим рассмотрение нашего примера вложенной системы и исследуем меню самого верхнего уровня Настройки. Мы имеем модель со следующими опци- ями: Цвет, Шрифты, Порты, Мышь, Рабочий стол, Клавиатура, Принтеры, Региональные установки, Дата/Время, 386-улучшенный, Драйверы, Звук и Выход. Подчеркнутые бук- вы показывают, какую клавишу надо нажать, чтобы выбрать данный пункт. Итак, для обработки данного меню нам требуется другая модель. Если в этой модели мы делаем какой-либо выбор, то, как правило, активируется еще одно меню, со свои- ми пунктами, а значит и со своей моделью и так далее.
Вложенные автоматы — это, по сути, единственный практический способ рабо- ты со сложными системами. Если вы исследуете стандартный проект, построен- ный на основе автоматов с конечным числом состояний, то увидите, что хорошие разработчики поступают точно так же. Они используют вложение своих моделей. В результате реализация проекта имеет те же самые вложения. Практика показы- вает, что без специальных инструментов очень трудно работать с таблицами со- стояний, имеющими более нескольких сотен входов. Это не очень много — всего 10 состояний и 20 входных кодов. Большие автоматы с сотнями входов постоянно используются в программном обеспечении, управляющем работой телефонных узлов, но некоторые подобные таблицы требуют сотен лет работы одного челове- ка для создания, тестирования и отладки. 9.3.5. Улучшаем модель Вероятность возникновения ошибок при создании модели достаточно велика. На практике модели на основе автоматов с конечным числом состояний требуют боль- ших трудозатрат. Вы должны уметь различать ошибки модели, ошибки в тестах, ос- нованных на этой модели, и ошибки системы. Легче избавиться от ошибок модели- рования до того, как вы начали разрабатывать тест, чем потом искать их во время тестирования. Ниже описаны некоторые вещи, которые с тоит поискать в моделях, и то, как их искать. Здесь нам сильно облегчает задачу то, что для таких моделей раз- работана теория, на основе этой теории созданы алгоритмы, и во многих случаях су- ществуют инструментальные средства, основанные на этих алгоритмах. Однако не спешите радоваться. Данная теория выходит за рамки этой книги, а алгоритмы, если они реализованы в инструментах, почти всегда предназначены для аппаратного обес- печения и должны быть адаптированы для использования в программных моделях. 1. Завершенность и последовательность. Как много у вас входных символов? Как много состояний? Произведение этих двух чисел (называемое произве- дением состояние-символ) равно числу ячеек в таблице состояний. Каждой ячейке в таблице должен соответствовать один и только один переход, не больше и не меньше. Если какая-либо ячейка не заполнена, то в модели воз- никает неопределенность. Если для какой-либо ячейки определен более чем один переход, то возникает противоречие. Программа не может быть противоречивой или незавершенной. В любом состоянии она всегда долж- на выполнять какое-либо действие для любого входа, и это действие долж- но быть единственным. Мнимые противоречия более неприятны, так как с ними ваша система с конечным числом состояний по крайней мере в два раза больше, чем вы думаете. 2. Однозначная входная кодировка. Если входное кодирование изменяется от состояния к состоянию, то у вас либо ошибка в модели, либо ужасный про- ект. Это означает, что размер вашей таблицы состояний не фиксирован. На практике вы не сможете проанализировать эту ерунду. 3. Минимум автоматов. Вы создаете модель, в которой у вас есть два набора со- стояний с различными именами, но одинаковыми выходными действиями
и аналогичными переходами. Предположим, у вас есть два состояния А и В, такие, что любая входная последовательность, начинающаяся в состоянии А, выдает на выход такую же последовательность, как если бы она начина- лась в состоянии В. В этом случае внешний наблюдатель не сможет отли- чить эти два состояния. За исключением различия имен, эти два состояния эквивалентны и могут быть объединены в одно. Аналогичные рассуждения применимы и к набору состояний. Вам следует упростить модель, объеди- нив все эквивалентные состояния. Это можно сделать автоматически. За более подробной информацией стоит обратиться к [BEIZ90]. 4. Нет сильной связи. Если в модели состояний для программного обеспе- чения между рабочими состояниями нет сильной связи, то либо ваша мо- дель, либо ваш проект содержат ошибки. Что вы думаете о программе, со- держащей меню, активация некоторых пунктов которого возможна только после перезапуска системы? Вы можете выявить этот момент вручную для маленьких моделей. Для больших моделей существуют специальные ал- горитмы, лежащие за рамками этой книги. Также существуют алгоритмы для поиска недоступных состояний или наборов недоступных состояний. Подходящий алгоритм разбиения можно найти в [BEIZ90J. 9.4. Методы 9.4.1. Основы При проектировании тестов вам надо придерживаться принципов, описанных в предыдущих главах. 1. Идентифицируйте входы. Какие конкретно входные события вы собира- етесь учесть в модели? Дайте каждому событию свое имя и опишите его. Например, конкретные входные сообщения, принадлежащие конкретным входным доменам, фиксированная последовательность входов. В модели невозможно учесть все возможные входы, поэтому используйте не слиш- ком большое число входных событий (например, 10-20). 2. Задайте входное кодирование. Вы выбрали входное кодирование, которое будет использоваться в вашей модели. Оно может соответствовать такому же кодированию, использованному программистами, а может и не соответ- ствовать. Не включайте в модель такие функции, которые поддерживают- ся программным обеспечением, но которые вы не собираетесь тестировать. К примеру, если операционная система сама конвертирует указание курсо- ром и щелчок мышкой в выбор пункта меню, то вам не надо включать это в свою модель, считайте, что ваш вход приходит к вам уже закодированным (например, операционной системой). Вы должны проверять входное коди- рование, только если оно является частью реализации программы. 3. Идентифицируйте состояние. Состояния часто создаются в виде произве- дения множителей. Если это так, идентифицируйте множители и имейте
в виду, что каждой комбинации множителей будет соответствовать свое не- повторяющееся состояние и что произведение растет очень быстро и вам, возможно, будет необходимо использовать вложенные модели. Составьте список идентифицируемых состояний и дайте им имена, используя какую-либо систему. Получившиеся состояния должны исчисляться десят- ками, но не тысячами. 4. Задайте кодирование состояний. Если разработчики используют программ- ную реализацию автомата с конечным числом состояний [BEIZ90], то про- грамма может содержать процедуру кодирования текущего состояния и счетчик состояний. Если это так, то процедура кодирования состояния должна быть протестирована, однако это может представлять большую трудность в контексте чистого поведенческого тестирования. Если к про- грамме не применялось явное проектирование с конечным числом состоя- ний, то кодирование состояний является одной из задач вашей модели и мо- жет не содержаться в качестве составной части в программе. Тем не менее, вы должны проверить корректность кодирования в вашей модели. 5. Идентифицируйте выходные события Только самые простые модели име- ют одиночные выходные события, например, соответствующие выводу одиночного символа. Гораздо более часто выходные события состоят из по- следовательности действий. Идентифицируйте эти последовательности. Во вложенных моделях выходное событие представляет собой активацию мо- дели следующего нижнего уровня в иерархии моделей. Дайте имя каждому выходному событию, вне зависимости от того, является ли это событие еди- ничным или представляет собой последовательность действий. 6. Определите выходное кодирование. Если дизайн определяет систему с ко- нечным числом состояний, то перед вами, возможно, встанет задача про- тестировать выходное кодирование, созданное программистами, и это так- же представляет трудность в контексте поведенческого тестирования. Тем не менее, вы должны проверить, что ваше выходное кодирование (которое в итоге является только свойством модели) на самом деле соответствует тому, что происходит в реальности. 7. Постройте таблицу состояний и таблицу выходов и уберите из них все не- нужное. Это наиболее трудная часть работы, она требует наибольших за- трат времени и наиболее опасна с точки зрения возникновения ошибок. 8. Постройте тесты. Вам надо разработать три вида тестов: тесты для проверки входного кодирования, тесты для проверки выходного кодирования и тес- ты для проверки состояний/переходов. Первые два теста относятся только к вашей модели. Третий тест относится к программе (и вашей модели). Эти задачи и способы их решения обсуждаются ниже, в разделе 9.4.2. 9. Запустите тесты. Любое тестирование должно стартовать из начального со- стояния, дойти до заданного состояния, пройдя по пути через различные другие состояния, и в конце вернуться обратно в исходное состояние.
10. Для каждого входа проверьте переходы и выход. Это действие может быть нетривиальным. Здесь, как правило, требуется какая-либо помощь в проек- тировании. См. раздел 9.4.5. Ниже приведены некоторые тесты для корабля Enterprise. ПО > по ПО > 30 > по по > Р0 > по по > 30 > ЗН > ПН > РН > Р0 > по ПО > Р0 > РВ > пв > ЗВ > 30 > по ПО > 30 > ЗН > ЗН > ПН > РН > Р0 > по ПО > Р0 > РВ > РВ > ПВ > ЗВ > 30 > по Все тесты стартуют из начального состояния ПО. Из начального состояния тес- ты идут в заданное состояние наикратчайшим путем и возвращаются наикратчай- шим путем обратно в начальное состояние, создав, таким образом, петлю. Тесты добавляются так, чтобы обеспечить покрытие связей. Каждый следующий тест строится на основе предыдущего, более простого теста. Если вы выбрали набор обходов, обеспечивающих покрытие, то для каждого перехода у вас есть вход- ной код. У вас также есть выходное кодирование, соответствующее всем перехо- дам. Вы должны пройти в обратном направлении и по заданным входным кодам определить реальные входы, а по заданным выходным кодам — выходные дейс- твия, если они есть. Может показаться, что это необычайно трудоемкий процесс (и это может быть так на самом деле), однако технически он не сложен. Эти тесты представляют собой скорее экспериментальные исследования, при этом оптимизации тестов не уделяется особого внимания. Переходя от одного тес- та к другому, добивайтесь минимума изменений и кладите в основу каждого сле- дующего теста предыдущий тест, в котором вы уверены. В результате этого под- хода возникнет множество на первый взгляд избыточных тестов, однако такой подход гарантированно надежен. 9.4.2. Что необходимо проверить 1. Проверьте входное кодирование. Убедитесь, что в вашей модели входное ко- дирование соответствует его реализации. Если они отличаются, выясните, где ошибка в модели или в программе. Способ, при помощи которого вы смо- жете это проверить, зависит от того, что конкретно вы кодируете. Если вхо- ды представляют собой числа, то для проверки кодирования вы, возможно, сможете использовать метод тестирования доменов. Если символьные стро- ки — то синтаксическое тестирование или другую модель состояний. Так или иначе, вы должны подтвердить соответствие между обработкой вход- ных событий вашей моделью и программой и объяснить все расхождения. 2. Проверьте выходное кодирование. У вас должно быть сравнительно немно- го выходных событий или последовательностей действий. Дайте каждой из них имя. Если закодированный выход «А» означает «открыть файл, об- новить файл, закрыть файл, сообщить об исполнении», то вы должны убе- диться, что все эти действия имели место, причем именно в этом порядке.
Вы можете исследовать промежуточные вычислительные шаги, протокол активности файла, использовать символический отладчик... Однако какой бы путь вы ни выбрали, вы должны убедиться в том, что ваши выходные коды соответствуют последовательности действий в реальной программе и объяснить все расхождения, если такое соответствие отсутствует. 3. Находитесь ли вы в начальном состоянии? Методы, обсуждаемые в этой книге, предполагают существование хотя бы одного начального состояния, а также то, что в него можно попасть. В сложных системах может быть несколь- ко начальных состояний. Например, начальное состояние для операции, вы- полняемой одиночным пользователем, скорее всего, будет отличаться от на- чального состояния для сетевой операции. Вы не можете начать тест, пока вы не обнаружили и не исследовали начальное состояние. Сообщений про- граммы, что вы находитесь в начальном состоянии, недостаточно. В конце концов, это может быть как раз та ошибка, которую вы ищете. Начальное со- стояние обладает определенными свойствами, такими как список открытых файлов, используемые ресурсы, активные программы и так далее. Проверьте это. Если ваше начальное состояние представляет собой что-нибудь вроде начальной загрузки или загрузки в память, то вы должны проверить каж- дое состояние и каждый переход в этом наборе состояний. Это может быть достаточно сложно, если вы не используете соответствующие инструмен- тальные средства для вашей разработки тестов, так как подобные последова- тельности часто выполняются автоматически. Пошаговое отслеживание пе- реходов необычайно полезно при тестировании. 4. Доступны ли вам все выходные состояния? Как правило, программы содер- жат более одного выходного состояния или набора выходных состояний. При попадании в такое состояние запускается процедура выхода из вашей моде- ли. Наипростейший пример — состояние, в котором закрывается тестируе- мая программа. Однако далеко не всегда все так просто. К примеру, если я ре- шил закрыть свой текстовый редактор, меня просят подтвердить это. Если я подтверждаю свой выбор и у меня есть какие-либо открытые файлы, которые не были предварительно сохранены, программа спросит меня, хочу ли я со- хранить изменения. Это уже нетривиальный набор выходных состояний. 5. Проверьте состояния. Все ли требуемые состояния существуют? Целью об- хода через выбранное состояние является проверка существования состоя- ния и его доступности. Разумеется, вы должны иметь в распоряжении на- дежные средства, при помощи которых вы сможете владеть информацией о состоянии в любой момент времени. Обычно при тестировании программ такая возможность существует, особенно если есть явный счетчик состоя- ний и если разработчики позаботились об удобстве тестирования. Если у вас нет средств для идентификации состояния, тестирование, хотя в прин- ципе и возможно, становится гораздо более сложной задачей, и его описа- ние лежит за рамками данной книги. 6. Нет ли лишних состояний? Это тяжело определить, как теоретически, так и практически. Однако при помощи эвристического метода, описанного
ниже в разделе 9.4.3, вы, скорее всего, сможете обнаружить лишние состоя- ния, если они существуют. 7. Проверьте каждый переход. Каждому переходу соответствует потенциаль- ный выход. Точнее говоря, существует итог каждого перехода. Переход со- стоит из двух вещей: нового состояния и выхода, если он есть. Если суще- ствует пустой «выход», соответствующий переходу, он также должен быть проверен. Вы задали кодирование состояний. Это означает, что у вас есть подробные характеристики, которые будут однозначно идентифицировать состояния. Проверьте каждый компонент кодирования состояния. Однако вы можете быть введены в заблуждение вероятностью существования лиш- них состояний, обсуждаемых в следующем разделе. Также вы должны про- верить каждое выходное действие, определенное в кодировании выхода ва- шей модели, и особенно соответствующее пустому выходу. Убедитесь, что при пустом выходе на самом деле ничего не происходит. Если вы перешли в корректное состояние и ваши выходы (включая пустой) для этого перехода также были корректными, то с хорошей уверенностью можно сказать, что и переход был корректным. 9.4.3. Проверка лишних состояний В конечных автоматах, например, в реализации аппаратных средств, проблема поис- ка лишних состояний в общем виде необычайно сложна, хорошо проработана и пото- му не рассматривается в данной книге. Однако в тестировании программного обеспе- чения мы имеем дело не с общей проблемой, а с более простыми частными случаями. Для частного случая мы делаем допущения, которые не могут быть сделаны в общем случае например, мы можем знать, в каком состоянии в данный момент находимся. В другом случае задачу упрощает природа ошибок состояний в программе. Когда у нас в программном обеспечении есть лишние состояния, лишь в очень редких случаях их число ограничивается одним или двумя. Чаще мы сталкива- емся с удвоением числа ожидаемых состояний или даже числом состояний, пре- вышающим ожидаемое в 1000 раз. Лишние состояния возникают из-за скрытых закономерностей в поведении систем с конечным числом состояний. Один допол- нительный бит, дающий вклад в поведение состояния, удваивает общее число со- стояний. На рисунке рассматривается наглядный пример. Нижний автомат с конечным числом состояний — это то, что, как мы полагаем, мы тестируем. Однако либо из-за ошибок, либо из-за неполноты модели где-то возникает иной фактор, о ко- тором мы не догадываемся. Из-за ошибки, произошедшей во время одного из на- ших тестовых обходов, вместо перехода из А в В мы па самом деле переходим из А в В’, в параллельное гиперпространство. К слову, в программном обеспечении мы, как правило, имеем дело не с одним гиперпространством, а с тысячами и милли- онами их. Если все эти параллельные гиперпространства идентичны друг другу во всех отношениях (за исключением фактора, являющегося источником всех этих лишних состояний), то, скорее всего, мы не сможем их обнаружить при помощи конечного числа тестов. Однако в этом случае ошибка не представляет опасности.
Если же альтернативные системы с конечным числом состояний хоть немного от- личаются друг от друга, то мы это можем обнаружить. В чем тогда проблема? Ведь в итоге у нас есть всего лишь небольшое безо- бидное различие в поведении, которым можно легко пренебречь. Хороший воп- рос, требующий ответа. Как я уже говорил, параллельных гиперпространств обычно не одно, а миллионы. В большинстве из них небольшие расхождения действительно безобидны, и с ними можно смириться, однако во многих ги- перпространствах симптомы ошибок фатальны. Я всегда убеждался, что «бе- зобидные» несоответствия в поведении вырастают в серьезные ошибки. Вы не сможете заставить разработчиков волноваться по поводу «безобидных» симп- томов. Если вы доложите им о мерцании экрана или о том, что курсор мышки ведет себя не так, как должен, они лишь пожмут плечами. Однако если, иссле- дуя эти изменения в поведении, вы обнаружите сшибки, ведущие к аварии, и если вы будете делать это регулярно, то вы заставите их обратить на это внима- ние. Ищите фатальные ошибки экспериментальным путем. Меняйте параметры (такие как длина файла, контрольные коды, опции и т. д.), которые не должны оказывать влияния на переход, и наблюдайте, не увеличится ли несоответствие в поведении. Например, уведите курсор мыши дальше или заставьте экран мор- гнуть два раза. Следуйте в направлениях, в которых различие в поведении рас- тет, и вскоре вы вычислите набор обстоятельств, ведущий к фатальной ошиб- ке. Несколько часов тестирования и внимательного наблюдения за типичным PC-приложением, — и вы будете вознаграждены сбоем в программе или разру- шенной базой данных (однако убедитесь сначала, что у вас есть хорошие средс- тва резервирования и восстановления). Мы можем обнаружить лишние состояния в гиперпространстве, в точности повторяя каждый тест. Пройдите из начального состояния в заданное состояние и обратно (по возможности не используя команду RESET). Затем вы сравниваете все компоненты, имеющие отношение к текущему состоянию (например, откры- тые файлы, используемые ресурсы, состояние окна и т. д.), до прохождения теста с состоянием этих же компонентов после прохождения теста. Затем данный тест (в точности) воспроизводится, и каждый выход для каждого перехода сравнива- ется с предыдущим прогоном и со всеми остальными. Каждое повторение изме-
нения в поведении записывается1. Любые отклонения в поведении, даже если они безвредные, сигнализируют о наличии лишних состояний. Выполнение приведенных выше рекомендаций не гарантирует, что вы обнару- жите лишние состояния, если таковые существуют. В общем случае подобное по- ведение можно распознать единственным способом, выбирая различные пути из начального состояния в заданное состояние. Повторение тестов — это не лучшее, что вы можете сделать, однако это меньшее из того, что вы обязаны сделать. Если не повторять тесты, то вероятность обнаружения ошибки мала. Принцип точного повторения тестов не должен ограничиваться тестирова- нием поведения систем с конечным числом состояний. Воспроизведение любого теста описанным способом является превосходной идеей, поскольку ошибки, по- рождающие нежелательное поведение, характерное для системы с конечным чис- лом состояний, не могут знать, какой метод мы используем. Поэтому обязательно повторяйте свои тесты! 9.4.4. Иерархия покрытия Как и для других методов тестирования, для систем с конечным числом состоя- ний существует иерархия покрытия. Покрытие узлов само по себе почти ничего не может сказать. Более того, если разработчики уже провели тестирование про- граммы на нижнем уровне (например, было выполнено тестирование модулей), то, скорее всего, это тестирование обеспечит покрытие узлов. Главный объект при тестировании систем с конечным числом состояний — это переходы. Для тестиро- вания переходов мы сначала должны убедиться в корректности состояний (обес- печить покрытие узлов). Поэтому, как и для большинства методов тестирования, мы будем считать, что это минимум, необходимый для достижения покрытия свя- зей (переходов). Есть ли что-нибудь еще, кроме покрытия связей? На самом деле есть еще масса различных вариантов исследования графа, нс все они лежат за рам- ками данной книги и, что более важно, выходят за рамки интересов большинства тестировщиков, использующих этот метод. Иерархия покрытия здесь соответствует набору все более длинных последова- тельностей тестов. Длина последовательности теста определяется числом перехо- дов (или, что эквивалентно, числом входных символов). Существует целый раз- дел литературы, описывающей методы тестирования конечных автоматов. Я не буду останавливаться на описании этих методов (это заняло бы всю книгу), од- нако я могу дать некоторый обзор причин, по которым эти методы важны для нас. Мы делаем три важных предположения при использовании методов тестирова- ния систем с конечным числом состояний для программного обеспечения. 1. Мы, как правило, знаем состояние, в котором мы находились до каждого пе- рехода и в котором будем находиться после него. В общем случае, например, при тестировании интегральных схем у нас нет другого способа узнать это, ' Это не так сложно, как может показаться. Мы имеем в распоряжении превосходные инструмен- тальные средства (например, средства захвата/воспроизведения, см. главу 10) для выполнения такого сравнения.
кроме как путем наблюдения за поведением тестируемой системы (то есть за выходами). В некоторых случаях тестирования программного обеспече- ния (таких как при тестировании протоколов), при которых у вас нет ин- формации о внутреннем состоянии (например, системы, с которой у вас ус- тановлена связь), определить внутреннее состояние тестируемой системы невозможно1. Если у вас возникли проблемы с получением информации о состоянии, то основных методов, описанных в этой книге, будет недоста- точно. Лучше всего разрабатывать программное обеспечение таким обра- зом, чтобы эта информация была доступна. 2. Выходные действия в аппаратном обеспечении в большинстве своем до- статочно просты, например, подача выходного импульса на определенную ножку разъема. Однако таких переходов, которые могут вызывать возник- новение подобного импульса, может быть не один и не два. В таком случае вы не сможете с легкостью определить, является ли ваш выход правильным. Это значит, что случайная корректность здесь не исключение, а правило. В программном обеспечении выходные действия сложны и часто однознач- но соответствуют переходу. Из-за их сложности, зная выходное действие, легко можно определить соответствующий переход. Если они эквивалент- ны импульсам в линии, — например, такое может иметь место в программ- ном обеспечении, управляющем протоколами, — тогда задача тестирования становится гораздо более сложной, и вам, возможно, не будет хватать основ- ных методов, описанных в этой книге. 3. Рассмотрим природу интересующих нас ошибок. Мы можем искать ошиб- ки в спецификации. Это представляется проблематичным, и для этого тес- тирование систем с конечным числом состояний неприменимо. Если раз- работчики выполнили гигантскую работу, реализуя некорректную систему с конечным числом состояний, то обнаружить это невозможно, какой бы метод тестирования вы ни использовали. Мы предполагаем, что наша мо- дель корректна и что ошибки содержатся только в реализации этой моде- ли. Наиболее вероятной ошибкой в программе является не некорректное состояние или неправильный переход, а крупное явление, например, це- лые параллельные системы с конечным числом состояний, возникающие из-за скрытых параметров состояний. В качестве простого примера мож- но рассмотреть программу, предназначенную делать резервные копии каж- дые несколько секунд, для того чтобы в случае сбоя в системе можно было восстановить информацию, используя рёЗёрЁные файлы. Предположим, программа не в состоянии очистить все эти данные при нормальном выходе. Она очищает резервные файлы, но оставляет ключевой параметр состояния без изменений. При следующем старте программа пытается провести вос- становление (как ей сказано), однако «требуемые» резервные файлы не су- 1 Заметим, что современные разработчики интегральных схем внедряют в свои изделия большое количество дополнительных схем, чтобы сделать эту информацию доступной для приборов, тестиру- ющих продукцию.
ществуют, что ведет к аварии. Один ошибочный байт данных означает 255 альтернативных пространств, одно 32-битное слово — 4,3 миллиарда таких пространств. Если вы тщательно исследуете крошечные изменения в пове- дении, то можете узнать, в каком пространстве находитесь. 9.4.5. Активизация и предсказание итога Проблемы активизации и предсказания итога при тестировании систем с конеч- ным числом состояний как таковой не существует. «Активизация» заключается во вводе команд или входов, которые инициируют желаемый переход. Предсказание итога означает проведение выходного кодирования. Каждое из этих заданий тре- бует существенных затрат усилий, однако они просты и для их выполнения не нужны специальные методы. Они должны быть сделаны. Наибольшая ошибка, которую тестировщик может здесь допустить, — эго отнестись к этим пунктам невнимательно. Вы действительно должны определить все до мельчайших дета- лей. Это несложно сделать, используя соответствующие коммерческие инстру- ментальные средства, такие как захват/воспроизведение, обсуждаемые в главе 10. Тестирование систем с конечным числом состояний наиболее эффективно не при первоначальном тестировании программного обеспечения, а при его повтор- ном тестировании, после внесения в него изменений в ходе сопровождения. Оно проводится с целью убедиться, что вещи, которые не должны были меняться, на самом деле остались неизменными. В таком случае предыдущий прогон теста дает нам как требуемые входы (обеспечивает активизацию), так и итоги. 9.4.6. Подсчет состояний Наиболее важное дело тестировщика (и особенно независимого) заключает- ся в подсчете числа состояний, числа входных кодов, а затем и их произведения состояние-символ. Программисты, которые не учитывают поведение систем с ко- нечным числом состояний, реализуют конечные автоматы с триллионами состоя- ний и миллиардами входных кодов. Они не могут быть протестированы должным образом ни сейчас, ни в будущем. С точки зрения тестировщика, такие ущерб- ные программы ломаются с необычайной легкостью. Системы с конечным чис- лом состояний, основанные всего на нескольких переменных факторах, растут очень быстро. Рассмотрите задачу 6 из упражнений в конце главы, чтобы почув- ствовать это самим. Одно время я заниматься разработкой логики и усвоил, что должен проводить формальный анализ любого конечного автомата, если произве- дение состояние-символ превышает 12, так как это число уже превышало грани- цы моих возможностей интуитивного тестирования дизайна. Для проверки кор- ректности конечного автомата с произведением состояние-символ порядка сотен необходимы месяцы работы, если только в состояниях и переходах не существу- ет закономерностей. В этих случаях совершенно необходим формальный анализ (остающийся за пределами данной книги). Затраты же на автоматы с произведе- нием порядка тысяч превышают годы или века работы одного человека — здесь ничего нельзя сделать интуитивно.
Из вышесказанного можно сделать вывод о том, что имеет смысл делать, а что не имеет. Предположим, вы исследовали систему и определили, что поведение системы задается пятью факторами с 7, 13, 8, 4 и 3 возможными значениями каж- дого из них соответственно; вы также определили, что возможные выходы (после кодирования) включают 42 отдельных действия. Произведение этих чисел дает 366 912. Как тестировщик вы должны просмотреть документацию для каждого из этих переходов. Если это невозможно, то программа не тестируема и ненадежна. Разумеется, разработчики могли бы реализовать вложенные машины, и мы наде- емся, что они так и сделали. В этом случае вам надо будет протестировать шесть гораздо более простых автоматов. Поиск значения произведения состояние-символ (для не вложенных автома- тов) — это самое простое и эффективное дело, которое вы можете сделать, тес- тируя системы с конечным числом состояний. Сделав это на первом этапе, вы сможете узнать, может ли ваша программа быть адекватно протестирована и, сле- довательно, будет ли она устойчива к сбоям. 9.4.7. Средства поддержки и тестируемость Это как раз та проблема, где программисты могут и должны отрабатывать свое жа- лование. Я решительно настаиваю на том, чтобы программисты использовали яв- ные реализации конечных автоматов (то есть задаваемые таблицами), если произ- ведение состояние-символ больше десяти. В [BEI7.90] описывается необходимый порядок работы. Если это условие выполнено, а проект тщательно проработан и легко поддается анализу (и, следовательно, вероятность ошибок в нем невелика), то следующие характеристики существенно облегчат вам тестирование. 1. Явный счетчик состояний. Существует одна заявленная переменная, или адрес ячейки памяти, которые определяют состояние в любой момент вре- мени. Эта информация доступна и может быть записана. Текущее состоя- ние также всегда известно. 2. Основной сброс и сброс в определенное состояние. Существует множество вариантов сброса, например, основной сброс в начальное состояние. Он, в свою очередь, может представлять собой полный сброс (все заново иници- ализируется), только восстановление состояния (меняется только счетчик состояний, а статус файлов и прочее остаются без изменений) или возврат в определенное состояние. Сброс может быть достаточно тщательно прора- ботан и может иметь достаточно много параметров, точно определяющих, что именно должно быть изменено (кроме счетчика состояний). Хорошие средства сброса чрезвычайно важны в больших автоматах состояний, где для того, чтобы попасть в заданное состояние без использования механизма сброса, пришлось бы пройти через множество других состояний. 3. Пошаговое выполнение. Это означает возможность пошагового прохожде- ния графа состояний, по одному переходу за шаг, а в случае выполнения со- ставных выходных действий — одно выходное событие за шаг. После каж- дого перехода предусматривается пауза, пользуясь которой, тестировщик,
если тест выполняется вручную, мог бы разобраться, что произошло. Если же тест выполняется в автоматическом режиме, то специальные инструмен- ты запишут всю необходимую информацию. 4. Трассирование переходов. Это означает запись отметки о каждом совер- шенном переходе. В понятие отметки входят входной код, инициировав- ший переход, текущее состояние, состояние после перехода, выходной код. 5. Явная таблица входного кодирования. Мы предполагаем, что существует явный механизм кодирования входа. Лучше всего, если он содержится в виде таблицы. Входное кодирование полностью отделено от последующей обработки данных. 6. Явная таблица выходного кодирования. То есть осуществлено явное коди- рование выхода. Оно может представлять собой таблицу, в которой указано, какие подпрограммы надо вызывать, или определен какой-нибудь другой отдельный механизм, не являющийся частью остальной обработки. 7. Явная таблица состояний-переходов. Это означает, что реализация систем с конечным числом состояний всегда имеет явную таблицу переходов. Самое удобное в этих таблицах то, что если обнаружена ошибка перехода, то ее на- хождение можно легко определить. Эти характеристики лучше всего встраивать в модель в самом начале, так как их сложно потом модифицировать. Очевидно, для таких средств нужны специаль- ные модели и команды управления, доступ к которым должен быть запрещен для пользователей без специального разрешения. 9.5. Рассмотрение приложений 9.5.1. Индикаторы приложений Ниже описаны некоторые типичные ситуации, требующие использования тести- рования конечных автоматов и/или приложения, в которых этот метод часто ис- пользуется. Более подробно эта ситуация рассматривалась в [AVRI93, BAUE79, WILK77], 1. Программное обеспечение, управляемое при помощи меню. Разработчики коммерческих программ, управляемых при помощи меню, как правило, используют явные конечные автоматы при проектировании своих меню. В том числе они используют метод тестирования систем с конечным чис- лом состояний для проверки корректности своих меню. 2. Объектно-ориентированное программное обеспечение. Модель с конечным числом состояний встречается в большинстве объектно-ориентированных парадигм проектирования. Корректное тестирование методов подразумева- ет корректное тестирование поведения состояний. В этом случае необходи- мость использования методов тестирования систем с конечным числом со- стояний очевидна.
3. Протоколы. Обсуждение методов тестирования протоколов лежит за рам- ками данной книги. Этому вопросу посвящено много книг, и во всех них предполагается, что вы владеете методами тестирования систем с конечным числом состояний [CHOW88, HOLZ87, SARI87, SIDH89], 4. Драйверы устройств. Большинство устройств ведут себя как системы с ко- нечным числом состояний, и большинство драйверов включают в себя та- кие системы. 5. Замена аппаратных средств. Задачи, некогда возложенные на аппаратные средства, в настоящее время все чаще решаются программным способом. Это касается не только электроники, но и механических и электромеханических устройств. В статье, приведенной в журнале Scientific America [GIBB94], предрекается использование микропроцессоров (и соответствующего про- граммного обеспечения) в выключателях света, электробритвах (2 килобай- та), автомобильных трансмиссиях (30 килобайт кода), ТВ (500 килобайт). Существенная часть поведения подобного программного обеспечения реа- лизуется как поведение систем с конечным числом состояний. 6. Инсталляционное программное обеспечение. Программное обеспечение, предназначенное для инсталляции и конфигурации программ, часто ведет себя как система с конечным числом состояний и может эффективно тести- роваться при помощи соответствующих методов. 7. Программное обеспечение для резервирования и восстановления. Програм- мное обеспечение, задачей которого является резервирование и (особенно) восстановление, по многим признакам ведет себя подобно системе с конеч- ным числом состояний. Мы наблюдаем рост числа двухпроцессорных фай- ловых или сетевых серверов. Такие системы традиционно тестируются при помощи методов проверки систем с конечным числом состояний. 9.5.2. Предположения об ошибках Предположения, которые мы можем сделать, будут относиться скорее не к приро- де ошибок, а к программному обеспечению, обладающему поведением системы с конечным числом состояний. 1. Специализированный конечный автомат. Программист может не догады- ваться, что его программа во многих случаях ведет себя как система с конеч- ным числом состояний. Вследствие этого отсутствует должный анализ, не- возможно выполнить адекватное тестирование и может быть сделано много, действительно много ошибок. 2. Ошибки кодирования. Это могут быть ошибки входного, выходного коди- рования или кодирования состояний, вне зависимости от того, явное это ко- дирование или скрытое. Если входное кодирование реализовано в скрытом виде, то велика вероятность непоследовательного кодирования от состоя- ния к состоянию.
3. Неверный выход. Это может быть ошибкой кодирования или, если выход- ного кодирования в явном виде не существует, то, к примеру, неверным вы- зовом подпрограммы. 4. Непредвиденное поведение состояния. Большое увеличение числа допол- нительных состояний может быть вызвано скрытой особенностью поведе- ния состояния. 5. Пересечение границ вложений. В реализации используются вложенные ко- нечные автоматы, однако из-за плохого, сделанного на скорую руку проекта или ошибок в нем, границы вложений игнорируются. На следующем рисун- ке показана модель, состоящая из нескольких вложенных конечных авто- матов. Каждая замкнутая область изображает набор состояний (например, меню). Если разрешим переход из состояния X, например, в состояние Y, то все система вложений будет нарушена, и на деле поведение в целом будет таким, как если бы вложений не было совсем. Существуют другие спосо- бы завершить подобное пересечение границ вложений, но это должно быть реализовано аккуратно. Пересечение границ вложений в примере является общей ошибкой, однако в большинстве случаев оно может быть обнаружено при помощи метода тестирования систем с конечным числом состояний. Не было ли у вас когда-нибудь такого, что вы использовали программу, управ- ляемую при помощи меню, оказывались в пункте меню, которое не выбира- ли и спрашивали себя: «Как это я здесь оказался?» 9.5.3. Ограничения и предостережения 1. Большие графы состояний. Методы, описанные в данной книге, применимы к не слишком большим графам состояний (произведение состояние-символ порядка сотен). Для больших, не вложенных графов состояний, подобных тем, что используются в управлении телефонными узлами, в которых про- изведение состояние-символ достигает порядка тысяч или десятков тысяч, способы проверки переходов, рассматриваемые в данной книге, слишком трудоемки, даже если разработка теста и его выполнение полностью автома-
тизированы. Это не может радовать. Положительная сторона этого вопроса заключается в том, что люди, работающие с такими большими системами, обладают необходимыми инструментами и опытом, чтобы использовать бо- лее совершенные методы, чем рассматриваемые в данной книге. Если у вас нет достаточного опыта и необходимых инструментов, вам не стоит браться за тестирование таких больших конечных автоматов. 2. Вложенные модели, или вложенные системы? Чтобы модели были рацио- нальны, необходимо использовать вложенные модели, поскольку, скажем, не- вложенная реализация может содержать миллиард состояний. Предположим, вы построили прекрасную вложенную модель, однако реальная программа мо- жет не являться вложенной структурой. Ваша модель охватывает лишь часть реального поведения, и покрытие связей в вашей модели никоим образом не означает покрытия связей всей системы с конечным числом состояний. Ваша модель — это всего лишь подсистема реальной системы, причем подсистема с хорошим поведением. Поэтому все ваши тесты могут успешно пройти, а про- грамма, тем не менее, будет содержать огромное количество ошибок. Нам важ- но иметь в распоряжении инструменты, показывающие, какие именно реаль- ные состояния и переходы были проверены. Такие инструменты полностью бесполезны, если только у вас конечный автомат нс реализован в явном виде. В таком случае вы можете винить только себя, поскольку именно вы не выяс- нили, является ли реализация вложенной, как и ваша модель, или нет. 3. Отсутствие поддержки. Средства поддержки и аспекты тестируемости, описанные в разделе 9.4.7, предназначены для облегчения тестирования и повышения его эффективности. Степень этой поддержки также является мерой того, насколько сложно или просто будет проводить тестирование системы с конечным числом состояний и насколько эффективны будут тес- ты при поиске ошибок. 9.5.4. Автоматизация и инструментальные средства Как всегда в разделе, описывающем автоматизацию, я могу вас порадовать и рас- строить. Порадовать тем, что проблема автоматизации разработки тестов для про- верки конечных автоматов исследуется уже более 30 лет, и в результате этих ис- следований появилось множество эффективных алгоритмов. Однако почти все подобные исследования были посвящены вопросам тестирования логики аппа- ратных средств, обладающих своими ограничениями и ошибками, которые отли- чаются от ограничений и ошибок, возникающих при тестировании программных конечных автоматов. Исключением является тестирование протоколов, для кото- рого аппаратная модель, возможно, будет эффективна. Инструменты, в том виде, в каком они есть, обычно интегрируются в более универсальные LSI (Интеграция Высокого Уровня) системы проектирования, и, по существу, недоступны тести- ровщикам программного обеспечения. На самом деле коммерческие средства поддержки разработки программно- ориентированных тестов существуют [POST94], но они находятся в зачаточном
состоянии. Большинство организаций, разрабатывающих программное обеспече- ние, которым приходится проводить тестирование конечных автоматов в больших объемах, разрабатывают свои инструменты [МАТТ88]. Поскольку эти инструмен- ты дают им ощутимое преимущество, они никогда не публикуют результаты и ни- когда не делают эти инструменты доступными для посторонних. 9.6. Резюме Модель конечного автомата является фундаментальной моделью тестирования, применимой к большому числу различных видов программного обеспечения. Она начинается с определения таблицы состоянийпереходов, включающей все воз- можные комбинации состояние-входной символ. Как правило, в большинстве мо- делей так же требуется входное и выходное кодирование. Обеспечение покрытия связей (переходов) является минимальной разумной целью тестирования. При использовании несложных средств поддержки, таких как явный счетчик состоя- ний, и сброс для нахождения большинства ошибок будет достаточно простых об- ходов. Самое актуальное из того, что тестировщик может здесь сделать — это со- считать произведение состояние-символ, и, исходя из этого, оценить, реально ли в данном случае выполнить тестирование. Следующее по актуальности дело, из тех, что тестировщик может сделать — это в точности повторить каждый из проводи- мых тестов (это относится не только к тестипованию систем с конечным числом состояний, но и ко всем тестам), используя систему захват/воспроизведение. А за- тем необходимо исследовать даже самые тривиальные изменения в поведении для того, чтобы обнаружить скрытые ошибки в поведении систем с конечным числом состояний. 9.7. Вопросы для самопроверки 1. Дайте определение следующих терминов: полностью определенный граф состояний, текущее состояние, выходное состояние, конечный автомат (ав- томат с конечным числом состояний), скрытое поведение системы с конеч- ным числом состояний, начальное состояние, набор начальных состояний, входное кодирование, входное событие, входной символ, номер входного символа, изолированное состояние, программа, управляемая через меню, вложенные системы, пустой вход, пустой выход, число состояний, выход- ное кодирование, входное событие, таблица выходов, доступное состояние, сброс, переход самого в себя, код состояния, стабильное состояние, счетчик состояний, произведение состояние-символ, таблица состояний, таблица состояний-переходов, сильно связанные, обход, изменяющиеся состояния, переход, недоступное состояние, рабочие состояния. 2. Переделайте модель корабля Enterprise, исходя из предположения, что три положения ручки управления двигателем находятся в вершинах треуголь- ника, а не вдоль одной линии (поскольку это желание рулевого Клингона,
а Клингоны всегда добиваются того, чего хотят). Это означает, что возмож- ны следующие дополнительные входы; р> з и з> р. Законы физики, тем не ме- нее остаются прежними для Клингонов. Разработайте новый набор тестов. 3. (а) Добавьте в модель корабля Enterprise главный двигатель (Г). Вы може- те перейти к главному двигателю из любого положения двигателя (Р, Н, 3), Однако конечный результат в любом случае будет один и тот же — движе- ние вперед. Главный двигатель не подчиняется законам Ньютона, поэто- му, если вы двигались в обратном направлении, то при включении главно- го двигателя вы можете перейти непосредственно к движению вперед, без промежуточной остановки. После выключения главного двигателя рычаг управления двигателем находится в положении, которое он занимал пе- ред включением главного двигателя, но вы продолжаете двигаться вперед. Создайте модель и разработайте тесты. (б) Задание, аналогичное 3(a), но для флагмана Клингонов Spklchutrgr Hrngrtch. 4. Компания La Forge модернизировала главный двигатель так, что теперь после его выключения он восстанавливает направление движения (вперед, назад, остановка), которое имело место перед его включением. Создайте мо- дель и разработайте тесты. 5. Если вы работаете в оболочке операционной системы Windows, спроекти- руйте модель меню наивысшего уровня в этой среде, разработайте тесты и выполните их1. 6. В моем полноприводном пикапе «Тойота-Терсел» на рукоятке переключе- ния передач нарисованы следующие передачи: к (задний ход), N (нейтральная ющая ручка для переключения между приводом на два и на четыре колеса, педали сцепления и тормоза. Вот некоторые правила управления этой ма- шиной* 2: • Переключая передачи, вы должны пройти через нейтральную передачу, то есть реальные действия по переключению передач будут следующи- ми: N>N, N>R, N>SL, N> 1, ... R>R, ... N>2, N>3, ... R>N, ... 5>N. Переключатель режима работы трансмиссии имеет только два положения: 2ВК>4ВК и 4ВК>2ВК (ВК — ведущие колеса). Сцепление может быть включено (есть) или выключено (нет). С тормозами дело обстоит точно так же. Вы мо- жете отпустить педаль сцепления (и включить его), если сцепления нет, ’ В формальном курсе я, как правило, использовал максимально возможное число примеров управляемых при помощи меню программ, исходя из возможностей доступных для студентов ком- пьютеров и/или операционных систем. Однако примеры корабля Enterprise и «Тойоты» разработаны так, чтобы в них сложность моделирования возрастала постепенно. 2 Я это не выдумал. Это описание — наиболее близкое к типичному описанию 2/4 колесной транс- миссии, из тех, что я мог привести. Сейчас у меня полноприводная машина, но у нее автоматическая коробка передач. И я рад, что инженеры, разрабатывающие автоматическую трансмиссию, использо- вали модель конечного автомата и соответствующее тестирование.
и нажать на педаль (и выключить), если оно есть. То же самое относит- ся и к тормозам. • Вы можете переключиться из любой передачи (за исключением SL) на нейтральную без использования сцепления. Переключение SL>N требует сцепления. • Вы должны использовать сцепление для переключения нейтральной пе- редачи на любую другую. • Передача SL вам доступна только в полноприводном режиме. • Вы можете переключиться между режимами 2ВК>4ВК и 4ВК>2ВК, не ис- пользуя сцепление, если только ваша передача отлична от SL, однако при этом вы должны стоять на месте, или двигаться вперед. » Любое переключение передач или выбор 2/4 приводного режима мож- но совершить, используя или не используя сцепление, если вы стоите на месте. • Если вы двигаетесь назад на передаче R, вы можете переключиться на первую или вторую передачу следующим образом: R>N> 1, R>N>2. • Единовременное переключение между передачами переднего хода не должно быть больше, чем на две скорости в любом направлении. Это зна- чит, что возможны следующие переходы: N>1,1>N>2,1 >N>3, 2>N> 1, 2>N>3, 2>N>4, 3>N> 1, 3>N>2, 3>N>4 3>N>5, 4>N>2, 4> N>3, 4>N>5 и так далее. Вы всегда можете переключить передачу на нее же саму (включая R и SL), ис- пользуя сцепление или без него, если только вы не проходите через ней- тральную передачу. К примеру, переключение будет 3>3, а не 3>N>3. • Нельзя пытаться совершать запрещенные переключения (такие как 5>N>R), ведь не секрет, что даже лучшие трансмиссии ломаются при не- правильном обращении. • Вы можете выполнять только одно действие за раз. Это значит, что нель- зя одновременно переключать скорость, режим работы трансмиссии, вы- жимать сцепление и тормоз или обе педали сразу. Определите входную схему кодирования. Разработайте таблицу(ы) состо- яний, включающую все запрещенные переходы. Разработайте набор тестов, обеспечивающий полное покрытие. Разрабатывая тесты, руководствуйтесь общими соображениями, имея в виду, что ваши тесты могут быть потен- циально опасны и/или могут иметь разрушительные последствия для ма- шины. Ваша задача — получить достаточно небольшой набор эффектив- ных тестов, представляющих собой обходы состояний и не разрушающих трансмиссию во время работы. Не пытайтесь разработать по настоящему минимальный набор тестов, так как это является сложной теоретической задачей. Приведенные ниже модели расположены в порядке возрастания сложности. Проработайте их. 6.1. Привод только на два колеса, нет очень низкой скорости, только три передние скорости.
6.2. То же, что и 6.1, но с четырьмя передачами. 6.3. То же, что и 6.1, но с пятью передачами. 6.4. Привод на два/четыре колеса, нет очень низкой скорости, только три передние скорости. 6.5. То же, что и 6.4, но с четырьмя передачами. 6.6. То же, что и 6.4, но с пятью передачами. 6.7. Привод на два/четыре колеса, есть очень низкая скорость, только три передние скорости. 6.8. То же, что и 6.7, но с четырьмя передачами. 6.9. То же, что и 6.7, но с пятью передачами. 6.10. Любое из приведенных выше заданий, но с дополнительным условием, что вы можете за один раз повышать скорость на три передачи (например, 1>N>4), а понижать только на одну (например, 4>N>3). Подсказка. Входное кодирование не обязательно должно соответствовать единичному входному событию, но может обозначать целую последо- вательность событий, как, например, 4>3 обозначает 4>N, N>3. Вложенные автоматы, состояния, и/или входы вы определяете, исходя из своих соображений. Не приравнивайте G>G к G >N>G (где G — любая передача), они не эквивалентны.
И нстру мента л ьн ые средства и автоматизация 1П 10.1. Обзор В этой главе приводятся аргументы, используемые для того, чтобы убедить людей вкладывать деньги в автоматизацию инструментов тестирования. Делается обзор особенностей инструментов тестирования и дается долгосрочный прогноз буду- щего тестирования. 10.2. Основные термины Внешние термины: побочный продукт, кэш-память, код, компилятор, данные, порча данных, отладочный пакет программ, функциональная надежность, редак- тировать, время выполнения, ЛОЖЬ, формальные методы, горячая линия, инспек- тирование, интерпретировать, прерывание, клавиатура, быстрый набор на кла- виатуре, аппаратные средства, инициализировать, сопровождение, размещение в памяти, многозадачность, сеть, объектный код, объектно-ориентированное про- граммирование, операционная система, оптимизирующий компилятор, бумажная лента, рабочая характеристика, пиксел, платформа, обработка побочного продук- та, программа, программист, качество, случайный, остаток, экран, SMART-DRV, про- граммное обеспечение, исходный код, упреждающее исполнение команд, опера- тор, текстовый редактор, пропускная способность, истина, пользователь, текстовой процессор. Внутренние термины: все определения, все пути определение-использование, все пути, все использования, утверждение, поведенческое тестирование, ветвь, ошибка, дерево, составной предикат, компонент, поток управления, поток дан- ных, тестирование доменов, рабочая среда, отказ, взаимодействие характеристик,
ввод, инструментальное оснащение, тестирование интеграции, связь, модель, итог, вывод, путь, предикат, структурное тестирование, синтаксическое тестирование, система, ошибка проектирования теста, тестовый сценарий, тестировщик, тести- рование модулей, проверка. 10.3. Обязательная автоматизация Моя цель в этой главе состоит не в том, чтобы убедить вас в необходимости ав- томатизации тестирования, потому что если вы не верите в это, то не станете чи- тать эту книгу. Моей целью является помочь вам четко сформулировать аргумен- ты, используемые для доказательства важности капиталовложений в технологию тестирования гипотетической корпорации Феррингов, которые являются про- тивниками формального тестирования, нс говоря уж об инструментах автома- тического тестирования. Некоторые дополнительные подробности об автома- тизации тестов можно найти в [FREE88, HEND89, MILL86, NOMU87, PERE86, VOGE80]. Для меня одной из самых удручающих картин является образ человека, ко- торый вручную делает на клавиатуре то, что может быть сделано автоматически. Это и грустно, и смешно. Мы живем в пятом десятилетии от начала производства компьютеров, а некоторых из нас все еще нужно убеждать в пользе компьютеров. Автоматизация тестирования — это тот самый случай. Э го забавно, так как всего век назад достиг своего совершенства паровоз. А за пятьдесят лет до этого между- городные почтовые кареты тащились упряжкой лошадей с верховым на первой лошади, который управлял всей упряжкой. По мне. так ручное тестирование — это то же самое, что всадник перед ускоряющимся локомотивом. Это опасно, унизи- тельно и совершенно нелепо. Если бы человеческое достоинство и оптимизация оплаты труда были бы единственным доводом в пользу автоматизации, как это было в прошлом, то ар- гументы по автоматизации тестирования проходили бы мимо ушей. Это не те ар- гументы, которые можно использовать для доказательства важности инвестиций в автоматизацию, так как бухгалтер с творческим подходом всегда сможет найти слабое место в ваших аргументах. А аргумент очень прост — ручное тестирование уже не работает. Оно никогда не работало очень хорошо, не работает сейчас и не будет работать в будущем. Ручное тестирование является самообманом. В нем по- нятие результата заменяется просто тяжелым трудом. И, что самое плохое, приво- дит к ложной уверенности в успехе. Если же вам не хватает самоуверенности, то существует гораздо более дешевый (как законный, так и незаконный) фармаколо- гический способ ее получить. Ручное проведение тестирования не работает. Первый миф, который должен быть рассеян, — это вера в то, что ручное выполнение тестирования работает. У нас есть превосходная статистика ошибок ручного ввода, составленная за многие дни набора на клавиатуре. Профессиональная машинистка совершает в среднем три ошибки на 1000 нажатий. Это было легко определить, так как за первоначаль- ным вводом следовал повторный ввод с клавиатуры, во время которого второй
оператор контролировал первого. Сравнение первых действий со вторыми проис- ходило полностью автоматически. Обычный тест содержит 250 символов. Тестировщик, который не является оператором печатающего устройства, не обладает высокой точностью специаль- но обученного оператора. Следовательно, нам следует ожидать, что большинство тестов, исполняемых вручную, имеют по крайней мере одну ошибку, проистекаю- щую из неверного нажатия на клавишу. К тому же, в отличие от оператора печа- тающего устройства, для которого проверка была автоматизирована (более 60 лет назад), при ручном тестировании проверка выполняется визуально. А визуальная проверка является процессом даже более подверженным ошибкам, чем собствен- но набор. Люди даже не знают, как высока частота появления ошибок при ручном тестировании, потому что без автоматического средства выполнения невозмож- но записать, как много попыток выполнения теста было сделано перед тем, как тест все-таки выполнился корректно, если это произошло. По моему собственно- му опыту, уже 20 лет назад использование примитивных инструментов автомати- ческого исполнения, таких как бумажная лента или телетайп, окупалось, так как ручное выполнение тестов было настолько ненадежно, что практически являлось бесполезным занятием. Ручное тестирование приводит к ошибочной уверенности в успехе. Выполнение теста руками является делом трудным, скучным, грубым и бесчеловечным. Человеческая природа, будучи именно тем, чем она является, особенно это каса- ется западной культуры, имеет тенденцию уравнивать усилия с результатом: «Мы так тяжело работали, у нас должно получиться хорошее тестирование!» Ошибкам не важны человеческие усилия. При тестировании поощряется обнаружение оши- бок, а не усилия сами по себе. Тем не менее, большие усилия необходимо мотиви- ровать. А основная ложная мотивация для ручного тестирования состоит в том, что это должно быть эффективно — иначе для чего бы мы так тяжело работали? Это и есть статистически не подтвержденная ложная уверенность. Ложная уверенность греет душу. Если это то, что нужно, то гораздо лучше не тестировать вовсе. Требование надежности обуславливает использование автоматического тес- тирования. В течение обычного дня я выполняю более 800 000 операций с раз- личными накопителями на магнитных дисках. В этом легко убедиться, просто использовав команду SMARTDRV/s в конце дня. В какой-нибудь из этих операций мо- гут проскальзывать ошибки, но, к счастью, относящиеся к аппаратным средствам или операционной системе, и я их игнорирую. Я не могу вспомнить, когда я в по- следний раз обнаруживал искажение данных программой. У меня есть причины ожидать, что я буду использовать свою систему в течение следующих 10 лет без потерь и искажений данных. Мне хочется пожелать того же самого для остальных 100 миллионов пользователей PC. Если бы компания Microsoft хотела обеспечить гарантию статистической стабильности (с помощью теории надежности програм- много обеспечения), то есть чтобы никакая из их платформ никогда не допускала потерю или искажение данных в результате действий с диском, потребовалось бы 100 тестирующих машин, работающих 24 часа в сутки, выполняющих 1000 тестов в секунду, и все это примерно в течение 3 миллионов лет.
Пользователи требуют от нас очень высокой функциональной надежности. Все статистически обоснованные методы оценки функциональной надежности программного обеспечения основаны на совершенно автоматических методах тес- тирования; и, как вы можете видеть, даже с такой автоматизацией все, что необхо- димо для пользовательской надежности, не может быть легко проверено. Люди не могут следовать шаблонам стохастического тестирования, необходи- мого для обеспечения всех известных оценок надежности программного обеспече- ния. Так что, пока вы в своем уме, вы не будете верить случайности. Какой же вы- вод можно сделать о функциональной надежности программного обеспечения по результатам ручного тестирования? Да никакой! Абсолютно никакой! И еще раз никакой1. Вы не можете подтвердить качество объекта на уровне 10 9, если точ- ность тестирования составляет 10"1. Как часто применять тест? Неудачи при попытке обоснования использования ручного тестирования обычно основаны на грубом просчете в количестве приме- нений тестов. Под «грубым просчетом» я подразумеваю просчет на порядок (или даже больше). Если вы полагаете, что тест должен проводиться только один раз, то использование автоматического тестирования будет трудно аргументировать. Но почему же люди недооценивают количество проходов теста? Прежде всего они не учитывают ошибки при проектировании теста. Тестировщики точно так же не защищены от ошибок, как и программисты. Если у нас есть хороший тест, т. е. тест, который обнаружил ошибки, то он должен быть запущен дюжину раз. По крайней мере три раза для отладки теста. Три раза для подтверждения того, что появились те же самые ошибки. В этом случае заново продемонстрируйте их программисту, который также захочет убедиться в том, что ошибки повтоояются. Таким образом, мы получили уже около 10 запусков теста. Затем еще два или три раза тест запус- кает программист во время исправления ошибки. Затем для подтверждения ис- правлений тест еще два или три раза запускает тестировщик. Двадцать запусков — это самая низкая оценка, так как мы еще не учитываем всех менеджеров, которых необходимо убедить. Если же, как это часто случается на более поздних стадиях тестирования, ошибка уже не является простой ошибкой, которую можно объяс- нить одним компонентом, а проистекает из взаимодействия между компонентами, то результат можно смело увеличивать втрое. Если тестирование эффективно (то есть находит большинство ошибок), тогда средняя оценка количества повторных прогонов тестов для всех тестов (тех, которые обнаруживают ошибки, и тех, кото- рые не обнаруживают) очень высока. На этот счет нет надежных статистических данных, так как это не принято запи- сывать, здесь изложен мой собственный опыт. Помимо автоматического выполне- ния на обычной бумажной ленте, мы использовали также майларовую перфолен- ту (эта лента, в 10 раз дороже обычной бумажной ленты, изнашивала ленточный перфоратор значительно быстрее), так как обыкновенная бумажная лента не мог- ла выдержать многократные повторные прогоны. Я точно не знаю, но, вероятно, через 40 или 50 прогонов через устройство считывания с ленты обычная бумаж- 1 Однако можно сделать много выводов относительно несовершенства ручного тестирования и его подверженности ошибкам.
ная лента начинает изнашиваться. Так спросите сами себя: были ли мои тестиров- щики попросту некомпетентны, или же из этого можно извлечь урок? Мир технического обслуживания [PIGO94], Современный процесс разработки программного обеспечения состоит не только из создания и тестирования нового кода, но также из поддержки существующего кода. Для большинства продуктов программного обеспечения около 80 процентов усилий тратится на техническую поддержку, как на корректирующее сопровождение, которое исправляет обнару- женные ошибки, так и на прогрессивное сопровождение, которое модернизиру- ет и добавляет новые возможности. В течение типичного цикла сопровождения модифицируется менее 5 процентов кода. Однако это обычно приводит к необ- ходимости комплексного регрессионного тестирования (то есть повторения на- иболее важного подмножества из набора первоначальных тестов) [BURK88], Общепризнанный опыт при проведении ручного регрессионного тестирования заключается в отказе от его использования. Одно из двух приносится в жертву — или прогрессивное тестирование (тестирование новых характеристик), или экви- валентное тестирование (тестирование неизменных характеристик), или даже оба вместе. Это опасная ситуация, так как в развивающемся продукте его сопровожде- ние может являться причиной ошибок, количество которых сравнимо с количест- вом всех остальных ошибок. Программисты сопровождения защищены от ошибок не более, чем тестировщики и программисты исходного кода. Попытки провес- ти ручное регрессионное тестирование (в действительности его не применяют) приводит к возрастанию число ошибок сопровождения до недопустимо высоко- го уровня. Сколько в действительности стоит ручное тестирование? Стоимость ручно- го тестирования практически невозможно оценить, так как информационная ин- фраструктура, необходимая для проведения точных исследований, возникает только после выполнения автоматизации тестирования. Но мы можем опреде- лить общую стоимость труда, если посмотрим, сколько людей занимается тести- рованием. Это должно быть выполнено корректно, что практически невозможно. Вам необходимы общие данные о трудозатратах, в первую очередь включающие в себя стоимость сервиса, стоимость горячей линии и тому подобное. Если стои- мость программного обеспечения определена корректно и должным образом свя- зана с различными видами деятельности, в таком случае большинство организа- ций, которые проводят такую оценку впервые, будут просто потрясены реальной стоимостью ручного тестирования. 10.4. Базовый пакет инструментов 10.4.1. Основы В этой главе я не ставил перед собой цель дать всеобъемлющий обзор инстру- ментов тестирования. Это заняло бы всю книгу. Для обзора текущих инструмен- тов я рекомендую [FSTC83, GRAH91, GRAH93, DAIC93, MARC94 и SQET94]. Коммерческие инструменты эволюционируют так быстро, что создание хорошего
и всеобъемлющего руководства невозможно, за исключением разве что периоди- ческих публикаций. Цель этой главы — рассмотреть инструменты тестирования в перспективе и обсудить важные технические особенности, на которые вам следует обращать внимание при выборе коммерческих инструментов или при их разработке. Нет инструмента, который бы точно соответствовал обсуждаемым характеристикам; любой инструмент представляет собой смесь таких характеристик. 10.4.2. Инструменты для покрытия Эта книга посвящена поведенческому тестированию. Нс в конце концов то, что мы тестируем, — это просто кусочки программы. Программы, обладающей неко- ей структурой. Как мы можем узнать, что наше тестирование выполнено хорошо? Здравый смысл говорит о том, что по меньшей мере каждую команду на уровне объекта следует выполнять в процессе тестирования. Поведенческое тестирова- ние основано на модели программы, но не на самой программе, а модели могут быть ошибочными. Поэтому модель тоже необходимо проверить. Ключевой час- тью проверки является то, что модель должна надлежащим образом отражать по- ведение, заложенное в реально существующее программное обеспечение. Если мы протестировали все части нашей модели, но не протестировали весь код, значит наша модель нельзя назвать качественно разработанной. Цель инструментов для структурного покрытия — дать нам техническое за- дание и количественную оценку того, какую часть программы мы фактически выполним при тестировании. Необходимо обеспечивать охват в 100 процентов. Если мы используем методы поведенческого тестирования, нам по-прежнему сле- дует контролировать покрытие структуры, чтобы знать реальное положение дел. Каждый метод тестирования содержит в себе метрику покрытия, которая измеря- ет степень применимости метода. В тех случаях, когда метод имеет структурный прототип, для подтверждения реальности покрытия следует использовать соот- ветствующий инструмент структурного покрытия. Б тех случаях, когда нет оче- видного структурного прототипа, вам следует записать или же определить преде- лы, в которых ваши тесты обеспечивают покрытие. На данный момент существует достаточно много источников информации об инструментах для структурного покрытия различных типов. Для получения до- полнительной информации по коммерческим инструментам я советую обратить- ся к руководствам [GRAH93, DAIC93, MARC94, SQET94], Ниже представлены основные категории инструментов структурного покрытия. 1. Покрытие потока управления. Наименее эффективный способ — это по- крытие операторов исходного кода, что является простым покрытием узлов и поэтому практически бесполезно. Однакс инструменты, предлагаемые рынком, обеспечивают измерение степени покрытия операторов — ис- точников потока управления. Этого явно недостаточно. По крайней мере, должно быть обеспечено покрытие ветвления. На практике, особенно для таких языков как С, которые поддерживают составные предикаты, дав- но известно, что простого покрытия ветвления (звена потока управления)
недостаточно и что каждый предикат составного предиката должен тести- роваться (по крайней мере) для значения ИСТИНА или ЛОЖЬ. Большинство ком- мерческих инструментов обеспечивают все три метрики покрытия — опе- раторов исходного кода, ветвлений в исходном коде и покрытие условий в исходном коде предиката. Инструменты для покрытия потока управления действуют (как правило) посредством автоматической модификации исходного кода, добавляя тех- нологические операторы, которые будут регистрировать пути и сегменты программы, реально работающие при проходе тестов Все эти инструменты обладают некоторыми потенциально важными огра- ничениями, о которых вам следует знать. • Различные компиляторы. Все инструменты покрытия содержат в себе компиляторы или их эквиваленты. Так как компилятор инструмента тестирования и рабочий компилятор часто сделаны разными производи- телями, то их объектные коды могут различаться. Для надежности тес- ты, произведенные при помощи инструментов, следует повторить с ре- альными компиляторами для подтверждения того, что итоги полностью совпадают. • Верхний предел объема кода. На сегодняшний день инструменты по- крытия фактически ограничены объемами сегментов исходного кода в пределах от 30 000 до 50 000 строк. При возрастании размера не только время выполнения тестов становится слишком большим, но и возраста- ет вероятность неверно отследить выполнение каждого сегмента. • Обработка условного ветвления. Компиляторы используют отложенное вычисление, в котором оценка предиката заканчивается при определе- нии значения истинности предиката. Это значит, что можно попытаться покрыть все предикативные условия (ИСТИНА/ложь), но обычно так не дела- ют. При современной оптимизации компиляторов, при продолжающей- ся оптимизации аппаратных средств и при наличии средств упреждаю- щего исполнения команд и кэш-памяти нет гарантии, что инструмент покрытия покажет то, что происходит на самом деле. Предикаты могут быть покрыты при тестировании, но это может не дать полной картины поведения тестируемой системы. Советую быть внимательными. • Искусственная среда тестирования. По своей природе инструменты тес- тирования работают в искусственной среде. При этом прерывания, мно- гозадачность, кэширование памяти и многие другие средства операцион- ной системы и аппаратуры либо не работают, либо работают по-другому (не так, как они это делают в действительности). Поэтому советую вы- полнить все тесты еще раз в реальной среде. 2. Покрытие блоков (профайлеры). Как мы можем покрыть тестами объект- ный код системы, состоящей из нескольких миллионов байт команд, если возможности инструментов для покрытия тестирования модулей настоль- ко ограничены? Вы можете использовать инструменты покрытия блоков
или профайлеры. Профайлер не пытается интерпретировать выполняемые команды (как делает нормальный инструмент покрытия), а просто реги- стрирует изменение данной области памяти (выполнение команды на объ- ектном уровне). С практической точки зрения это настолько же хорошо, как и регистрация исполнения ветвей операторов и предикатов в исходной про- грамме. Профайлеры могут обеспечить такое покрытие данных для отдель- ных байтов, отдельных команд объектной программы или блоков из байтов или команд. Покрытие объектов может быть выполнено для каждого исполнения ко- манды, в этом случае результаты будут очень четкие, но неточные, так как система тратит большую часть времени на измерение самой себя. Такая форма называется детерминистическим покрытием. Альтернативной фор- мой является периодическая выборка выполнения команд. Это называется статистическим покрытием. Преимуществом статистического покрытия является то, что режим тестирования реалистичен и влияние, которое ока- зывают инструменты покрытия, можно аналитически скорректировать. Не- достатком же является то, что для получения статистически достоверного измерения надо провести тысячи повторений тестов. 3. Инструменты для покрытия потоков данных и других покрытий. Хотя тес- тирование потоков данных определяется здесь в контексте поведенческо- го тестирования, существуют соответствующие структурные концепции и связанные с ними инструменты покрытия. Уже разработаны инстру- менты, которые измеряют все использования, все определения, все пути определение-использование и даже все пути [FRAN85B HORG92, KORE85, OSTR91]. Ни одного из них не было в свободной продаже к 1994 году. Существуют также инструменты покрытия (коммерческие) для регистра- ции высокоуровневого тестирования, которое не обсуждалось в этой книге, например, покрытие древовидных схем, которые необходимы при тестиро- вании интеграции. 10.4.3 . Автоматизация проведения тестирования Автоматизации проведения тестирования следует уделить первоочередное вни- мание, так как даже умеренная автоматизация разработки тестов сразу же со- здает огромное число тестов, которые бесполезны без автоматического исполне- ния. Во многих системах и средствах разработки программного обеспечения есть возможность на 95 процентов или больше автоматизировать выполнение тестов. Стопроцентное автоматическое выполнение, по всей видимости, нежелательно. Это точно нежелательно, если единственная возможность это реализовать — со- здать сложного робота-наборщика, который будет имитировать действия пользо- вателя с клавиатурой и мышью. Если автоматизацию проведения тестирования принять во внимание с самого начала и если это будет обязательным условием при проектировании системы, то возможна очень высокая степень автоматиза- ции выполнения — около 99 процентов. Основной инструмент автоматизации
выполнения тестирования — это тестовый драйвер. Наиболее популярная форма тестового драйвера — это инструмент захвата/воспроизведения. 1. Наглядное, но плохое первое приближение. Наиболее общим первым при- ближением к автоматизации проведения тестирования является создание добавочного кода. Пишется специальная программа, в коде которой зало- жены все данные для тестирования, критерий соответствия и все остальное. Хорошо, но кто будет тестировать этот вновь созданный код? Должны ли мы «тестировать тестируемый код» или «тестировать тестирование тести- руемого кода», и если да, то выполняет ли этот подход покрытие и как быс- тро? Это не лучший способ работы. Только в исключительно редких слу- чаях оправдано создание специализированного программного обеспечения для тестирования. Как правило, универсальные инструменты тестирования, типа драйверов, в которых исходные данные теста и ожидаемый результат рассматриваются как данные, а не как программный код, удовлетворяют большинству потребностей тестировщиков. 2. Тестовый драйвер (существуют сотни доступных, коммерческих и свобод- но распространяемых драйверов) используется для проведения автомати- ческого тестирования [CONK89, HOLT, 87. PANZ78], Законченные драй- веры (хотя таких драйверов на данный момент немного) должны иметь все приведенные ниже особенности. Используйте это как памятку. Существуют три определенные фазы управления тестированием: начальная установка, выполнение и постпроцессинг. Соответствующие инструменты структур- ного покрытия могут быть (должны быть) частью пакета. « Фаза начальной установки. Подтвердите конфигурацию аппаратного/ программного обеспечения, ведь иначе вы не узнаете, действительно ли вы работаете в той среде, в которой собирались? Загружаются и ини- циализируются требуемые заранее или совместно используемые компо- ненты. Инициализируются другие необходимые аппаратные средства и программное обеспечение. Устанавливается доступ к требуемым струк- турам данных. Инициализируются инструментальные средства и инс- трументы покрытия. » Фаза выполнения. Каждый тест необходимо инициализировать долж- ным образом. Без этого инструмент тестирования не может стать средс- твом автоматизации исполнения. Загружаются и контролируются вход- ные данные для каждого теста. Оцениваются утверждения. Собираются выходные данные. По мере необходимости производится сброс инстру- ментального средства для каждого теста. • Фаза постпроцессинга. Используется подходящий критерий соответс- твия результатов теста. При аварии сообщается об отказах теста. С по- мощью интеллектуальных методов сравнения сравниваются реальные и прогнозируемые итоги (методы позволяют определять, что надо учи- тывать при сравнении и в какой степени). Данные о выполнении пере- даются в инструмент покрытия. Подтверждается правильность путей.
Проверяется наличие лишних и побочных результатов. При отказе теста управление передается пакету отладки. • Захват/воспроизведение данных. Другие названия: захват/проигрыва- ние и запись/воспроизведение. На рынке коммерческие инструменты захвата и воспроизведения превалируют над другими инструментами автоматического тестирования. Я рассматриваю захват/воспроизведе- ние данных и при автоматизации исполнения теста, и при автоматиза- ции проектирования теста, так как он применим в обоих случаях. Захват/ воспроизведение данных является фундаментальным инструментом и наиболее популярным способом обеспечения перехода от ручного к ав- томатическому выполнению тестов. Инструмент захват/воспроизведе- ние работает в двух фазах, фазе захвата и фазе воспроизведения. В фазе воспроизведения он представляет собой просто тестовый драйвер. Фаза захвата будет обсуждаться в следующем разделе, который посвящен ав- томатизации проектирования тестов. 10.4.4 . Автоматизация проектирования тестов Цель автоматизации проектирования тестов — уменьшение усилий, затрачива- емых на создание тестов. Связь коммерческих инструментов с различными ме- тодами, обсуждаемыми в этой книге, рассматривалась в каждой главе и не будет повторяться еще раз. Достаточно сказать, что каждый метод, обсуждаемый в этой книге, может быть дополнен соответствующими инструментами или, по крайней мере, ощутимо улучшен при их использовании. 1. Захват/воспроизведение данных. Захват/воспроизведение данных — это инструмент, автоматизирующий проектирование тестов, так как он запи- сывает такие важные события, как вводы данных, нажатия на клавиши и так далее, а также отклик программного обеспечения (то есть выходные данные). Таким образом, он создает сценарий теста, который запускается во время фазы воспроизведения. Инструмент захват/воспроизведение мо- жет быть как простым, так и сложным, может записывать и воспроизводить все, начиная от единичного нажатия на клавишу и заканчивая пиксельным отображением экрана. Важность метода захвата/воспроизведения в отношении данных состоит в том, что это самый легкий способ перехода от ручного тестирования к авто- матическому. Захват/воспроизведение данных становится еще более мощ- ным инструментом автоматизации проектирования, когда он используется в комбинации с текстовым редактором. Обычно если вы работаете с серией тестов, вы обнаруживаете, что большинство входных данных не меняются от теста к тесту, и только небольшое количество входных и выходных дан- ных отличается. Таким образом, существует возможность запустить только один сложный сценарий и впоследствии создать различные варианты тес- тов, редактируя его. Если в процессе выполнения теста обнаруживаются ошибки, они исправляются путем редактирования. И вы можете быть уве-
рены в том, что ошибки в тесте не возникнут опять при следующем запуске. Это как раз то, что не может быть выполнено, и уж тем более доказано, при тестировании вручную. Инструмент для захвата/воспроизведения данных бесполезен без возможности редактирования тестов (например, при помо- щи текстового редактора). 2. Мультистратегические генераторы. К 1994 году на рынке был представлен только один коммерческий мультистратегический тестовый генератор — Т [IDEI94J. В основе генераторов, рассчитанных на одну стратегию, лежат эвристическое тестирование доменов, синтаксическое тестирование, вход- ные комбинации, случайные входные данные и другие, хорошие и не очень, существующие методы. Такие инструменты будут производиться и в даль- нейшем. Сейчас, когда вы знаете основные методы поведенческого тести- рования, вы можете оценить, понимают ли предполагаемые производители инструментов тестирования эти методы или же они только генерируют ни на чем не основанную эвристику. 10.4.5 . Рекомендации по выбору производителя инструментов тестирования Это не урок по оценке и выбору инструмента (может, к этой теме стоит обратить- ся в следующей книге?), а некоторые важные замечания, на которые следует обра- тить внимание при оценивании инструментов и производителей. 1. Съешьте сами то, что производите. Это я впервые услышал от Роджера Шермана из компании Microsoft. Если вы продаете еду для собак, вам не следует колебаться, перед тем как съесть миску своей собственной продук- ции. Вам может не понравиться вкус, но вы знаете, что это безопасно для здоровья. Спросите предполагаемого продавца инструментов, использовал ли он свой собственный продукт тестирования для себя. Если он затрудня- ется с ответом, уходите, так как он не доверяет своей продукции. 2. Подключение тестирующего средства. Инструменты тестирования не рабо- тают сами по себе. Инструменты тестирования встраиваются в более широ- кую среду разработки программного обеспечения и связанные с ней инстру- менты и методологии. Вам следует рассматривать не только преимущества инструментов, но также и легкость, с которой вы можете их интегрировать в вашу среду. Хорошие инструменты, которые не могут взаимодействовать с другими инструментальными средствами, встречаются довольно редко. 3. Поддержка. Не стоит ожидать бесплатной поддержки от производителей инструментов. Но вы всегда можете купить поддержку по приемлемой цене. Инструменты тестирования, подобно другим инструментам разработ- ки программного обеспечения, могут быть довольно сложны, особенно если в основе инструмента лежит запатентованный метод. Я знал производите- лей замечательных инструментов, выброшенных с рынка, так как они были
согласны продавать инструмент, но не поддержку, без которой инструмент просто ничто.' 10.4.6 . Не обманывайте сами себя Здесь приведена общая, но верная схема. Организация вкладывает инвестиции в инструменты тестирования. На каждом уровне организации существует стрем- ление к качеству. Войска готовы и полны энтузиазма. Каждый разработчик и тес- тировщик получают лицензионную копию инструмента. Через год спросите своих сотрудников, кто все еще использует этот инструмент. Несмотря на инвестиции, первоначальный энтузиазм и все остальное, таких будет менее 5 процентов. Что же произошло? Почему это случается так часто? Все недооценили время, которое было необходимо потратить на изучение ин- струментов и базовых методов, чтобы ясно понять, что данный инструмент и ме- тоды были эффективнее устаревшего ручного способа. Вы можете изучать материал этой книги в течение одного семестра базового университетского курса или же во время интенсивного пятидневного семинара, но вы не станете экспертом, пока не выполните упражнения и реально не попрак- тикуетесь с материалом. Без практики методы не усвоятся и, следовательно, ни- когда не станут частью вашей работы. В студенческой среде это происходит ав- томатически, потому что упражнения и практика растягиваются на длительный период времени (а экзамены, несомненно, доказывают эффективность практики). Такие механизмы отсутствуют в обычных производственных условиях. И управленческий аппарат, и тестировщик почему-то ждут, что они усвоят эти уроки при помощи волшебства, не тратя время на практику, и, что хуже всего, они ждут немедленного увеличения производительности. Но как же это может про- изойти? При реалистичном подходе на время изучения новых методов следует планировать снижение производительности и качества. За три-четыре недели на- пряженного труда вы освоите любой метод из этой книги, повысите с его помо- щью продуктивность и эффективность, а также научитесь использовать связан- ные с ним инструменты. 10.5. Будущее тестирования 10.5.1. Основы Я не верю и никогда не верил в тестирование, но я не буду летать самолетом, чье программное обеспечение не протестировано должным образом. И я не противо- речу сам себе. Я верю в независимое тестирование, но не в группы независимого тестирования. И опять же я не противоречу сам себе. 10.5.2. Зачем и почему я не верю в тестирование Тестирование является нашей последней линией обороны от ошибок, но не первой или единственной. Если при тестировании обнаруживаются ошибки, то это значит,
что предыдущая стадия процесса разработки программного обеспечения неполно- ценна. Предотвращение ошибок дешевле, чем их обнаружение. Для того чтобы про- двигать методы предотвращения ошибок и методы обнаружения первоначальных ошибок, такие как всесторонний анализ, создание прототипов, аналитические моде- ли, формальные методы и инспектирование, мы, как тестировщики, должны стре- миться поставить самих себя вне коммерции. Тестирование предназначено для об- наружения ошибок, которые остаются после выполнения предварительной работы, из-за того, что методы планирования и анализа слепы по отношению к ним. Подобно тому, как компиляторы исключают синтаксические ошибки из общего списка оши- бок, будущие инструменты будут устранять текущие ошибки из сферы деятель- ности тестировщиков. Объектно-ориентированное программирование и эволюция операционных систем подают надежды на то, что исчезнут многие общие ошибки межкомпонентного взаимодействия. Формальные методы могут уменьшить или исключить ошибки взаимодействия характеристик. Я не думаю, что тестирование на самом деле исчезнет, так как остающиеся ошибки (после усовершенствования процесса) всегда более неуловимы и опасны. Поэтому я ожидаю, что со временем тестирование станет более технологичным, чутким и эффективным. 10.5.3, Зачем и почему я не верю в независимое тестирование Как насчет независимого тестирования? Основная цель независимого тестирова- ния состоит уже не в том, о чем мы думали 10 лет назад Мы верили тогда, что не- зависимое тестирование оправдывается его беспристрастностью: только группа независимого тестирования может быть объективна. Это плохой аргумент, кото- рого мы не видим в других инженерных областях: «Нам нужен независимый ана- лиз нашего строительства структурного проекта, так как мы не можем доверить проведение компетентного анализа нашим инженерам». Вот какова гнилая основа независимого тестирования! Исторически основное оправдание существования независимого тестирования состояло не в его беспристрастности (несмотря на то, что мы это так громогласно утверждали), а в защите и выживании тестировщика. Цель существования груп- пы независимого тестирования — защита тестировщиков. Если в организации не развита культура контроля качества, такая защита существенна. В серьезной ор- ганизации, в которой контроль качества осуществляется на всех уровнях, такой довод для обоснования независимого тестирования неприменим. В этом случае можно верить в объективность разработчиков относительно оценки своей собс- твенной работы и нет необходимости защищать тестировщиков от разработчиков. Так что же тогда является достойной причиной существования групп независи- мого тестирования? 1. Защита тестировщиков и обеспечение объективности. Рассмотрим это как некоторую фазу, через которую должна пройти организация для того, что- бы достичь определенного уровня качества. Это особенно важно, если тре- бования качества диктуются свыше. Эго дает надежду на прохождение этой фазы. Группа независимого тестирования может быть расформирована и
направлена в разрабатывающую организацию, когда качество станет лич- ным делом каждого. 2. Проверка конфигурации на совместимость. Продукт, который должен ра- ботать на различных платформах и во многих различных режимах, может выиграть при организации независимого тестирования. Разработчику труд- но понять все нюансы программного обеспечения и все проблемы, характер- ные для многочисленных и сильно отличающихся друг от друга конфигура- ций. Группа независимого тестирования часто оказывается весьма полезна для проверки конфигурации на совместимость. Заметим, тем не менее, что такая группа использует другие тесты, отличные от тех, которые использу- ют разработчики. 3. Тестирование рабочих характеристик и производительности. Для боль- шинства продуктов программного обеспечения это не главная проблема, так как производительность и рабочие характеристики определяются тем, на что не влияет разработчик, например операционной системой. В тех слу- чаях, когда рабочие характеристики и производительность системы важны, для тестирования лучше привлечь соответствующею специалиста, посколь- ку здесь существенную роль играет аналитическое моделирование (напри- мер, теория очередей). 4. Тестирование сети. Вообще говоря, это особый вид проблемы тестирования конфигурации. Сетевое программное обеспечение имеет свои дополнитель- ные сложности, которые требуют знания вопросов теории сетей, особенно относящихся к протоколам. Это опять таки повышает требования к разра- ботчику, который должен быть не только экспертом в предметной облас- ти продукта, но и экспертом по сетям. В этом случае группы независимого тестирования могут быть полезны. Это не редкость, тестирование сети про- исходит на нескольких уровнях и может проводиться, хоть это и не обяза- тельно, различными организациями. И опять, независимые тестировщики выполняют иное тестирование, нежели разработчики. 5. Локализация. Появляются различные версии продукта для различных язы- ков или версии, которые должны удовлетворять правилам и/или требова- ниям, зависящим от конкретной страны или отрасли. Группа, ответствен- ная за локализацию, может проводить и независимое тестирование. 6. Понижение риска и жизненно важное программное обеспечение. Когда ставками являются человеческие жизни и/или существует вероятность воз- никновения проблем с законом в случае аварии, благоразумие (а не техни- ческая эффективность) может потребовать независимого тестирования, так как широко распространенное мнение говорит о том, что только такой спо- соб гарантирует объективность. Это на самом деле не является ненужной тратой сил, так как уменьшение риска проблем с законом оправдывает до- полнительные затраты. Однако при таком тестировании следует не просто повторять предыдущие тесты, а прилагать усилия к исследованию потенци- ально опасных ситуаций, не протестированных ранее.
10.5.4. Будущее тестирования Здесь я скажу о моих надеждах по поводу тестирования. 1. Тестирование становится стандартной частью образования разработчиков программного обеспечения. Подчеркну, не кратковременным факультатив- ным курсом, а обязательной частью образования программистов, предлага- ющей по крайней мере три различных области обучения. Предварительное тестирование (тестирование черного ящика), тестирование среднего уров- ня (интеграционное и системное тестирование) и тестирование высокого уровня (алгоритмы и теория тестирования). 2. Тестирование идет в ногу с развивающимся процессом разработки про- граммного обеспечения и с нарастающей сложностью программного обес- печения. 3. Производство инструментов тестирования исчезает в той форме, в которой оно сейчас представлено, и занимает законное место в качестве важнейшей составляющей индустрии производства инструментов для разработки про- граммного обеспечения. 4. Для большинства из нас тестирование перестает быть профессией, но остается неотъемлемой задачей, которую регулярно решает каждый добро- совестный разработчик. 10.6. Вопросы для самопроверки Дайте определения следующих терминов' захват/восприизведение, проверка конфигурации на совместимость, корректирующее сопровождение, метрика по- крытия, инструменты покрытия, детерминированный режим профайлера, фаза выполнения драйвера, фаза постпрограммы драйвера, фаза начальной установки драйвера, съешьте сами то, что производите, тестирование эквивалентности, отло- женное вычисление, локализация, сопровождение, сетевое тестирование, профай- лер, прогрессивное сопровождение, регрессионное тестирование, интеллектуаль- ный метод сравнения, статистический режим профайлера, структурное покрытие, тестовый драйвер, тестирование производительности.
Приложение А
Department of the Treasury - Intend Revenue Service I 1040 U.S- >гкИуИц*1 Income Tax Return___________________________1994__________[(99) jfrg. ми orafr — ba not wfc or щу*»ft*?ft*1 For the yea Jan 1 ~ Dec 31, 1994, or other lax begirvyn^ ,1994, ood>Oj ,19 Label Ycx* ЙРЙ ftM*W Yaw *4кЫ tacwHly Ha. Use toe WtSlabeL Otherwise, ptease pent or type* if « *мХ wtofR. vpouM'k twt n*»w LMinvn» rtam Mk>«M {ПЫГММГ «Ш tow#, Й you tww « l* О bw, **• Jntovdxxw. ApertrfwH ft*. C*j> to»** cr aocloMc*. И yOutew » «Лш, м« wttowtoMb. &Ы» W>C0* For Privacy Act and Paperwork ReducSwi Act Mode*, see Instructions. Do you want 53 to go to Ito* fund? Yes Filing Status 2 If a joint return, does your spouye want $3 to go to ш» fund ?..... "T Singto I .1 Married filing joint return (even rf only one had income) Check only one box. Exemptions Итоге man 6 dependents, see «nirs Income Attach Copy ВЫ If you did not pet a W^see wnttuction*. Enclose but do not attach any payment with your return »ц «□ Mamed filing joint return (even if only one bed income) Married fihng separate rtn. Enter spouse'» SSN etc vt & lull name here, ►.......... Mead of household <wrth quaMytng person). If the quaMying person is a chdd but not you dependent, enter ths child's name here . ..... ... **________________ 8 Г1 Quddytno widcw(er) 6*1J YowaaW, If your ран MaWtoww «SvHvMi •ensv* Jb Taxable amount with dependent chrto (year spouse died » 1$ -------- .., — parent (or someone ehe) can ctem you as a dependent on r»s or her lax return, do not Check box 6a But be sura to dwca the box on In 33b on pg 2. 15* Total IRA distribution*. 20b Form 1040 0994 fQiAClIZ ППУМ 19 Urwmpk-ytrwrri campensat.on. 20a Socte security benefits. I 2C 21 Other income *1 14 15b 16b c Dependents: 0)nxw (Mrt, жчеа, жМ we *е*м} <2)c* a «mW _*8SL (3) К «а» 1 w w»Jw, 4вр*г«Э*гГ» teoxf wu»<; ouKibtr (4) о«е«ч)мгс («Wtwib^ ’«•PS. tem* mtn mi i ♦ Total hunger of exemption* Ctemad . 7 Wapw, saianes, bps. ate Attach F«rn(s) W-2 •a Taxable interest income. Attach Schedule В i! емн 840Q b Yaxmxwnpt Krterest Doni include on line 8a. 9 10 DMdend mcome. Attach Schedule В if over $400. Taxable refunds, crodds, x offsets of stole and local income faxes 11 Актолу received 12 Би» n. «1 жат. w (Io»' Attwt ЫЛ»б . C o' C-E2 13 Capital gain or (loss). If required. Attach Schedule D. 14 Other oa*ns ©< Oossei). Attach Form 479? 16a Tot pensxms & annuities .. J 11$e. 17 Rental real estate, royalties, partnerships, S corporate^, trusts, etc. Attach Seb E IB Ferm incoma ©» (toss). Attach Schedule F . . ......................... Taxable amount Taxable amount 1» 22.Mdtbe amounts n the far njht column tor Ito»* 7 »21 TK. Adiu’dmxrVi 23a Your IRA deduction to Incom. Cautw Sm tnslructions . , bSpouse's IRA deduction .... 24 Молод expense*. Attach Form 3903 or 3903 F 25 One-half of «ЫйтфЬутап1 tax . ► 26 Setf-amptoyed neatth insurance deduction. ... 27 Uo»M «мл)tianMMf««tort. S»<MucL 26 Penalty on early withdrawal of savings 29 Mrw f*t RWpWt SSN * M ‘ dd Iw , 23» ttwusb 29. Tbe„ nre vtur tot* n*u- tmw.u ts you total Income. - 23» 23b 24 » 26 27 26 29 - Fl suwwx эо fcom w a tn* и миг м^мме «г*м йк«т. tr **» «ж» л л* VaWSS InCOOW м» Жеже mcwiw Сгми frjjwerxfwM МП
Еашашлж Тах Computation 32 Amount from fine 31 (edjteted grow income).............................................. 33a Ck (f: fl *<*» *** 65foidet. £j П Spouse was 65/оИвг» (j Blind Add the number of boxes «sheeted above and enter the low here..... ... *“ S3» b If you parent (or someone else) can cia#n you as в dependent, de here.... ► 33b c If you are wanted fifing separately end your spouse itetruzw deduebons w you ere » dual-status aiiao. see tm^ruefrom and check here....... ....► 33c 34 ttamtead deductions from Schedule A, Jine 29, or tarpr Standard bed siwwn betew fix your fe«ng status. But И you ckd any box on йие S3» or b, see msfructwns to find your standard _ded. If you checked box 33c, your standard deduction »$ zero. _ • Smgto - $3,800 ♦ Head of household ~ 35600 • Mamed King jorntty or Qualifying wteow(er) - 36.350 • Mamed fifing seporatety - $3,175 33 Subtract fine 34 from fine 32.. . Й you want the IRS to fr$ure your tax, see mstructAns. Credits Other Taxes Payments 36 37 38 39 49 41 42 43 44 46 46 47 48 49 Я 51 42 53 Attach Forms W-2, W-2G. •nd 1099-R ел оде к 54 Я м 67 W 5» Refund or Amount You Owe 62 « 64 65 И in 32 is 383,856 « less, mufticty $2.450 by the total no. of exemptions claimed on to 6e. и In 32 « over $83,850, see the instructions for the amount to enter.... Taxable income. Subtract in 36 from to36. if in 36 is more the to 35. enter 4k. Tax. Check if from « ’ J Tax Table, bi J Tax Rate Schedules, cfj Capital Gato Tax Worksheet., or, dQj Fwm 6615» Amount from FomXs) 8814 . Additional taxes. Ck if from..д J Form 4970 b[J Form 4972 Add fines38and39............... . , .... Credd for chekJ and dap care exp- Attach Form 2441 Credit for the ekJerty a the daebted. Attach Sch R. Foreign tax credit. Attach Form 1 B6......... _ »Ц Form3800 bO Form 8396 c?_J Form 8801 <J Form (spec) Other credits Check tf from Add line* 41 through 44 Subtract line 45 from fine 40. If fine 46 ts more than fine 40, enter 0-., Sett-emptoyment tex. Attach Schedule SE- Alternative minimum tax. Attach Form 6251........ .............. « 1 42 43 44 Recapture taxes, Ck it from Form 4255 bQ Form 8611 ЙForm 8828 SS and khtat» to л bp tficane «Я rwxto to wnckyer- AfteaFonnSij? Tax on qualified retirement plans, toduling IRAs If required, art Frm 5329 Advance earned income credit payments from Form W-2. Addlmtt-52.Tlw««uf tetottw ....................... feteai income tox wtiffrefet If vtfиfrom FoKO >Ж tit 1994 estimated tax payments and amourn applied from 1993 return..... ....... Earned Income credtt. If required, etl Sch EIC Nontaxabte earned income: amount * _________ and type ► w________________________________ Amount paid with Form 4868 (extension request) Excess social security and RRTA tax withheld.,.. Other payments Check if from 43 Form 2439 ti[j Form 4136 . ....... АйВД - и от yw tot< [»~ra H fine €0 n mere Uwi tot 53, subtract fiM S3 f«m fine 56. This is fht imaun jw Cteecpeid Amount of fine 61 you want Refunded to You.... AmtoflnS) youwOTAPfttMlteVeurlWSEOTM . H Я | If to 53 rt more then to 60, subtract in 60 from to 53. This is foe Amount You Owe. For details on how to pay, tnciuciing what to write on your pmnl, see instructions... Estimated tax penalty. Aho include <xi fine 64...........,,, J M | L«J u ' Sign Here Keep я copy of foil return for your records. Unw мге*н«f pwfixy. 1 Ом1м» «WI hrre «kwmmw! »w reiwm wrf гожчжугх? кпмМи end «Шепчп». W> »w ЫМе(«му*г«*й<^«а«И Okw are tn®, cvrect «м СОЯ»ЙЙ1. ОеОжМмн ев ю>ммге> Cw t**cw*i я Ъвмб о*: Wi rntasnahnn of Wytft, arveww fw« кжшЫ&№. УмгеюМмге ► Эш Vow врииееЧ нцмаи. М a jwnt <ж«1№, SKJTH autcl «ф». ► DU» Paid Pr«p*r»t's Preoetw* Hx>*fi** * Оме ОшЛМ erepwws toe to incuntf ек МУ егерв вуеС Г~: Us* Only Ге*яЖя*те (eryewre я * ГОЙ0ПГ «ИЛ*** SaPCtot
286 Приложение А Форма 2106 стр.1 Form 2106 Employee Business Expense оме ж, isreoi» ► Attach to Form 1<мю, ___________________________54 Ocrupetian ta ttfwft Юфвямк >*1 «ntwnvt «Untitled 1> > _ 11 Q Employee Business Expenses end Reimbursements Nota: ffyou wen not nlmbunaO Юг ony ertpenvn tn Sun I. step line 7 ant) enter the amount from ftne 6 on tine 8. Step 2 Enter Amounts Your Employer Gave You tor Expenses Listed in Step 1 7 Enter erwunta you emptoyer gave you that were rwA reported to you to box 1 of Form W-2. Include ary amount reported under code V to box 13 of your Form W-2 7 L* 1 f= * Step3 Figure Expenses to Deduct on Schedule A (Form 1040) 8 Subtract line 7 from Iuras fi............ Noto: //both columns of fc* Зжехет stop here. If column A is loss than xttro, report the amount as income on Form WO, fins 7. 9 In «Алта A, enter the amount from line в (rf zero or less, enter -0'>. In column B. multiply the amount on line 8 by 50% (,50).. W Add the amounts on fane 9 of both columns and enter the total here. Also enter the total on Schedule A (Form 164QK ime 20> (Qualrfted pertormsng artels and indwtouafe with disabilities, see frte «rstrucbons for special rules on where to erw the total) .... ...........................T. .........- - • • tn 81 For Paperwork Reductton Act Motto», *•« kwtrvcttone. Form 2106 (1994)
С&м jnMnxtons to find out xfrKft wctont to wimplate.) Section A - G*»v ral Information (»)Vfehfcie 1 ft) VohKl. 2 11 Enter the dete vehicle wm placed in servica. .... 11 12 Total miles vehicl» was used during 1994 12 miles miles 13 Buun*M mil» «KloOod on fin» 12 13 miles mi les M Percent of business use. Divide line 13 by line 12....... 14 “X x 15 Awrage daily round fry» commuting distance. 15 mi les mi les H Commuting miles included on Jew 12.. 16 miles miles 17 Other personal miles. Add lines 13 and 16 and subtract the total fromш» 12 17 miles miles 18 Oo you (wyou»«рои»)h»v» onottwv»Nc««evailaUoto»parwnalpwwM»?. . . .....................J_Jy«» LJ No 1# it you» «"ioloy« ptovKtod you with « vtthcks, « pr»wn»l u» Uunng off tfuty hows permitted? . .0 Yes Q No Q Not efitneaat» a Oo you heve evidence to ««port your tfedudkr?......... ...... ............................... CN 0* 21 It VftV tg the ft vtdenc» written? •XuD X«. П WO Section B — Standard МНевф-t R»t» (Use this so^tion only if you own the vehicle) , 22 Muhipty ling 13 by 29* (.29), Enter the result her» and on frne, L mad earners, see instructions) Section C - Actual Expwis*» 23 Qaioiin»» oi), repairs. vehcle insurance, etc.. 24a Vtfwde rental» .. t> Inclusion amount c Subtract Im 24b from line 24a 24 c 25 27 Value Ы employer •provided w»cie (applies only if 100% of annual И» v»be was inc4jded on Form W-2 see mstrudions)........ Add lines 23.24c. and 25 Multiply line 26 by the percentage on bne 14.,. D^xecmbon. Eater amount from line 38 below Add Im* 27 and 28. Enter Uxal bye and on hno 1............, Section P - Dpr»dfrtk>n ot Vatilcjw м» ttw »a>onif ife инэдк. 30 У1 sz 34 36 17 Enter cost <x other Ьа&я .,. &ttt amount at tec*» 17$ dotata Muitpty hr* 30 fcy Jine 14 fws instructions if you elected the section 179 deduction),,,, Enter depreciabon method and percentage.......... Multiply line 32 by the pwcaruaga on bn» 33,. Add lines 31 and 34 Enter the brratabon amount from the tabla in the toe 36 tnsfrucfrom.... MiAijJr lit» 36 by the pwcentag* on Enter «maber of line 35 <x line 37. Also enter this amount on line 28 &*« ................. - a » » » a
288 Приложение А Форма 2210 стр.1 Form 2210 Umhrnavmmri t>l Es&mfca Tax by Individual», Es»t»a and Trusts * See «operate Instructions. > Attach to Fom IftW, Form 1&40A, Form 1040NR, or Form 1041. cwueiMww 1994 06 Nw«w0} atwwn «п ш <чкп Hate: in moat case*, you do not need to Ab Farm 2210. The P?S fiaure any penalty you owe and send you а ЪШ. Frit Form 22/0 orY/ front or more boxtt tit Pen i apply toyou H you do not need to file Form 2210 you sW/тду use ft to ftgurt your penaty. Enter toe amount from tine 20 or tine 3# on the pena/fytine ot*wr return, M do not attach Form 221b. Reason* for Filing — It la, b, or c below ignites to you, you may be able to lower or etimmate your penalty. But you must check the boxes that apply end file Form 2210 with your fox return. If 1d betow applies to you, check that box and file Form 2210 with your tax return. 1 Chock whichever boxes apply Of none apply, see the Note above): «Q You request a waiver. In certain circumstances, the IRS wifi waive alt or perl of the penalty- See Waiver of Renaty*> the «reductions. r, You мм the anmiaBaad Income Instafcaeiit method. If you income varied during the year, th is method may reduce the amount ol one b|_J or more required insteament*. Sae the tnsVucbons. « You hod federal income lax withheld from wooes and you treat И as paid tor estimated tex purposes when it was «dually withheld t[_j instead of in equal amounts on the payment due dates. See the mVucbpns far Ine 22 Your required annuel payment {tine 13 below) « based on your 1993 tax and you filed or are filing a joint return for either 1993 or 1994 d, but not both years , faH и Required Annual Amount 2 3 1 5 1 , L I e 1 2Entef your 1994 tax after cradite SOthor taxes 4Add tines 2 and 3 ^Earned income credit S Cr«M for federal tex pe#d on fuels. ?Md tires 5 and 6 7 •Currwri ywr Hx SUXnd Ji<w 7 tr«n kn« 4 iMwtMylkwb Ь» L“ 1 • — lOWithhaktng ым> Ca not hcludt on, оь. ,»«od In payment, on v-4 kna. T! Subtract tint W from tine 8 If teas than $500. stop here; do not complete or file this form, You do not owe the penalty 11 UEntor the lax shown on your 1993 tax return (110% of that amount it the adjusted oross income stewn on that return я more than $150,000, or if married filing separate^ 1™™ than $75.000) Cautiea: Sot tiatfuctiont 1Z 1 MtequfrodaMwN payment Enter the amtetertrf tine 9 or tine 12.... ....... 1> Note: if tine 10 я equal to or mon than tine 13, stop hart, you do not owe the penatfy Do not fib Form 2210 units* you charted box Id above. JL ~ Shod Method (СаиОоа: Read toe inetrvctione toieeffyou can use the abort method. If you charted box lb orc tit _____________Fwf < sky tote p»t and pg- to Pwf /V)... 14€nter the amount, rf any, from tine 10 above ... ... ..... 1 (Enter the total amount rt any. ot estimated tex payments you made 14 Add bcm 14 and 15 17ТоЫ tawferpayment foryaer. Subtract tin* 16 from Ime 13. M zero or ten, stop hero: you do not owe the panatty. Do not file Form 2210 unlaw you checked box Id above WMtiply tine 17 by .05725 . . IMtf the amount on tine 17 was paid мое after 4/15/95, enter -0- • fr the amount on tine 17 was p«d before 4/15-Э5, make the following computation to find №e amount to enter on tine 19. 14 1$ JL if Amount Ort fine 17 Number of days pekl befora4/lS«6 .00025 SOFenatty. Subtract line 19 from line 18- Enter the result here and on Form 1040, tine 65: Form 1040A. tine 33; Form 1O40NR, line 66; or Form 104), line 26 -------------------------------- . Ciei For Paperwork Redudfon Act Notice, »ee Instruction*. Form 2210 OW)
fcwigio _____________________________________________________ Р®‘' Iv Regular Method (S« th» mstru Люсь it you ere tiling Farti 1040NP _-xi* Section A - Figure Your Underpaynv.r.t (•) 4/15/94 PlWWit Due Dates (t>) <« 6Л$94. %Л5ЛЭ4 (4> 21 Required Imrtallment*. tt box lb applies, enter the amount* fromSchedule Al line 2b Otherwise, entet IM of bne 13, Form 2210, in each column 22 Estimated Ua paid and tax withheld. For column (a) only, also enter the amount from ime 22 on line 2b. If line 22 is equai to or more than kne 21 for all payment penods stop here; you do not owe the penalty Do not file Form 2210 unless you checked ft box tn Pert 1 Complete tines 23 through 29 of one column before going to the next cohmn. 23 Otor inxvr, rf nyjrem tot 29 ef релхл сада. 24Addhrm22and23.. 25Mj даадй» on bnu 27 «rd 23 of th* pteeous wtvmn .... 26 Subtract line 25 from line 24. If zero or Cass, enter «0». For column (a) only, enter the amount from line 22 27 И toe amount on hne 26 « zero, subtract fcne 24 from hne 25. Otherwise, enter «О* 28Underpaynwnf if line 21 ts equal to <y more than tine । 26, subtract Une 26 from hne 21. Then go to line 23 of next column Otherwise. go to bne 29 * 28 290*epeynwcHto»2&umor«<tenw»Z1t«ubtr»d toeJItwi law Z£. Tten fi tekm ^3 of next 29 SfrCtkm В — Figure the Fenahy (Complete hnes 30 through 35 of one column before going to the next column) April 16» 1994 - June 30,1994 Rate Period! ЗОЧяпЬег of days from the date shown above line 30 to the date the amount on line 28 was paid or 6/30/94 whichever » earlier. ...... ** x numoeror " №%* . , .07 ,Uiy 1/1994 - September 30,1994 Rate Period 2 3ZNumbw pf days from the date shown above line 32 to the date toe amount on bne 28 was paid or 9/30/94 whchewt is earlier. ...... . . 33 Ufxterpeyment on Ine 28 x Reto Periods 93C<^4 WW______________1Л5/95 «Number of days tram the date shown above line 34 to the date the amount on line 28 was paid or 4/15/95, whtcbever n earfter............. . .......... c . . N<jmber 01 36 “ЖГ , ж 1_____________Д______________$ MPenalte. Add all the amounts on lines 31. 33, and 35 in all columns, Enlm the total here end cn Form 1040, hne 65; Form '040A, line 33J Form 1040NR, line 66: or Forrn 1041, 7tne 26 * » $ 10 Зак 770
Form 2688 tofrnwrf fhxwuM &еиэ (9t) Application tot Acuiuonal Extension of Time to ГИ«- U.S. individual Income Tax Return ► See fostruchoos. * You Must complete all Hem* that apply to yw. Ум w* rr ... • Mt L*ei name Й a *gM retom» нкми» *al "•<*• Mt tart IWM СМВНММДОИ 199ft ________El_ _ „ Yaw 9*«Ы S*MHf ИмшЬ** 8>*wW* tnW Swaxty femMr Нэт» (гыпмг. йм< eM «Mftowm тдЛ* er rw« nxto). X you пал * P.O. be*. м» №• ewbvctww, C4f- town « ptwl a№nt MPCocto 1 I request an extension of lime unW _______________«19_______» to fee Form (MOeZ Form 1D40A, or Fwm 1040 for the calendar year 1994. or other tax year ending 19 Z Have you filed Form 4868 to roquet an extonwon of feme to Hie for this tax year?.. . ..........Q Ye# Q He M you checked Yto,' we will grant your extension only foe undue hardship. Fully exptotn Iha hardship on line X 3 Explain why you need ал extension* И you expect to owe gm or peMratfoiwtopptog trrxfe (GST) tax, complete few < 4 If you or your spouse plan to file a 0ft tax return (Form 709 or 709A) far 1994, generally due by k Yourseft April 17t 1995, see the inslrud'tw» check here...... .................... ...... .....wl Spoue* ............ *| ] Signature ind Verification Under penalties of perjury, i declare that I haw examined this form, including accompanying schedules and statements, and to the best of try knowledge and beltat rt re Vue, correct» and complete; and» if prepared by someone other than the taxpayer that I am authorized to prepare tore form. WBMUteftftaxtHto* *" од WMMftfMKkm ► Ой»> <te tone jcW^f. ПСИН гадй «а» Я v&f «* hto •Iflnehntf WviMnv <еж»ж«мм|мум *• । । .. . .. L °** ** IWj*W*IBd<MC^TbtB$'Mate9¥Ww*Wrvrn*rw«W- — ~H»~ 9 artMIrrtumth* .#.___________________________________________________ Новее w Applicant — To Be Completed for the IRS BWe have approved your appikafexi. Pwasa attach this form to your return. We haw not approved your eppitcabon. Please attach this form to your return. However. because cf your reasons stated above, we have granted а Жоау grace penod from the date shown below or due date of your return» whichever re later. This grace penod is considered to be a velto extension of tone for elections otherwise required to be made on returns filed on time. Г~1 We have not approved your application. After coraucfering your reasons stated above, we cannot gran! your request for an extension of time to fife. We are not granting the W<day grace period. __ We cannot consider your appScatton because ft was filed after tne due date of your return. __ We have not approved your app&cafron. The maximum axteneion of time allowed by taw is 6 months Zj Othw_____________________________________ (Stnato ___________________________________ Br__________________________________________________________________________ ОйМ I s Him* If you w»nt the copy of this form returned to you at an address other than that shown etoove or to an P HunWwandМпмлvwMv,ram,waetne.)wПО 6в»twnWwXmwl• ndаййкйto«емй wkfrw* agent acting for you» enter the name of the agent ?? a Ofc, «mo orwatettce ZtHCwH and/or the address wbere the copy should be sent D1SI For Paperwork Redudtoo Act Новое «м toretrucUons. Form 2888(1994)
Form 3903 of Тлкммгу harm's) tfww* «в Form 10® Moving Expenses * Attach to Form 1046. * See separate ln»toucHo«$. ОИВМе. 15*е-ООЙ 1994 62 YwjraMMSMWte Hwwieef f-ii Moving Expenses incurred in 1994 CwVon: If you m » mtmbtr ot the аптяП >0K*t, s»t tb* tnstnicbom btforo compMing this part 1 Enter toe number of rrotes from ywr oto borne to your new wrttptees 2 Enter th© number of irate* from your oMIxhw to your ©idwwVpiece. 3 Subtoed line 2 from line 1- Ел ter the result but rarttes* than zero.. t* &w 3 at toast 50 ¥« •» Go to line 4. Ateo. see Ttow Teet in toe indtudton», He * You cannot deduct your moving expenses incurred tn 1994 Do not complete the rest of tots part. Sae the Itoto below if y&u also incurred mowig expenses before 1994, 4 Transportation end storage of household goods end personal effects 5 Travel and lodging expenses of moving from your ой home to your new home. Do not include meats. « Add teles 4 end 5.......... 7 Enter the total amount your employee pad for your move («кИад toe value of services furnished in kind) that is not mclucted in the wages box (box 1) of your W-2 form, This amount shewed be identified with code F m box 13 of your W-2 form.................................................. .............. to fine в more Шеп fine 71 Ye» * Go to line 8 Ho •* You cwmot deduct w moving expenses incurred in 1994, И line 6 is toss than hne 7, subtract fine 6 fromline 7 and include the result in income on Form 1040, fine 7. в Subtract Hne 7 from fine 6. Enter the result here and on Form 1040, fine 24, This is your moving expense deduebon for expenae* Incurred in 1994, Note* If you majfr^tf nwing expanses before 1994 and you fM npt dedbof !ho*e ejgjensas on a prfor year’* tax retom, comotete Parts II and Id on рада 2 to figura tba amount, if any, you may deduct on Schedule A, ftemoed Oeducfxw.
Схема налоговых ставок SE Si-heduM SE (КлиМЛ, Ммгя* * ,* !й>«л (99) Seif-Employ<nent Тах ► 5<Mf Instruction» for $сЛ«^й SE (Form 10*0). ► Attach to FomH МО, hem* <af pw*w< «вШ мЯ ww»<uymwt (*$ *hw« ол Form ICAO) 8ос»Ы security number of person with MtHtmploymem income > ОЫЙ ш im^oom “1994 17 Ano Must Flie Schedule SE You rrmi file Scfwduie SE if: • *w had net earnings from self-empteyment from other than Church employee income (itne 4 of Short Schedule SE or fine 4c of Long Schedule SE) of $400 or more, or • You had church employee income of $108.28 or more Income from services you performed ss a minister or a member of e геЬдкхд order Is not church employee rrwome. Hotei Even if yw new a k&s Of о smt>8 amount of income from s*^-»mptoyment, rf may be to your benefit to fife Schedule S£ end use ’apton# method* in Part II of Long Schedule SE. Ехсервшк » усам only wtf*emptoyment income was from earnings as a nw$tw, member of а religious order, or Ctmtten Sconce ргасЬЬосин < end you fifed Form 4#з1 and received IRS approval not to be taxed on those eamtngs, do not We Schedule SE. Instead. *Tite ’ExefT^t-Fofm 436Г on Form 1040. tine 47. May I use Short Scbeduk SE or MUST I use Long Schedule SE? Section A — Short Schedule SE. Caufirm: Peed obwe to see if you can use Short Schedule SE. t Ne! farm profit or (toss) from Schedule F, line 36, and farm partnerships, Schedule K-l (Form 1065), fine 15a .............................. ................................................................ Z Nel profit or (loss) from Schedule C. line 31; Schedule C-EZ. fine 3; and Schedule КЛ (Form 1065). fine 15a (other than farming). Meters and members of religious orders see instructions fix amounts to report on th» fine. See tmfruebons for other income to report. ..... . ........ ... 3 Combine lines 1 and 2 4 Hei taming» from aHrffrempiayrrwrrt, Multiply fine 3 by 92.35% (.9235). if less iha« $400, do no! file this schedule; you do not o*® selfremptoyment tax..... ... ......................... . . .. .... 5 Sell-empioyrnenl tax. If the amount on fine 4 «: * $60 80S or »«, multiply fine 4 by 15.3% (Л53). Enter the result here and on Form $046» line 47. • More than $60.600. multiply fine 4 by 2.9% (.029). Then, add $7,514.40 to the result Enter the total her» and on Form 1G40, fin* 47. 6 Oeducttofl for one-haif of seff-emplwment tax. Multiply line 5 by 50% (5). Enter the resuli hew jtfto on Form ltUa,line25 _ 5 , ... ___ &1B1 For Faperworfr Reduction Act Katie*» see Form 1M0 insteuefionib Schedule S£ (Form 104Q) 1994 FOlAilOI l0fl»?94
Form 1040 Une 10___________ shewn on return State and Local Tax Refund Worksheet 1994 ____________* Keep tor your records______________________________ Soci* Security Number 4a Entei the number from yoir 1993 Form 1040. line 33a .................. 4a 4b Multiply line 4a by S.’OO ($900 if your filing sta'us was single or liead of household)............................................................ . 4b S Add lines 3 and 4b , ........................... 5 6 Subtract line b from line 2. If zero or less, enter -0-............... 6 7 Taxable refund. Enter the smaller of line 1 or line 6 here and on Form 1040, line 10................................................................... 7 1 Enter state or local income tax refund, from Form(s) 1099-G (or similar statement) 2 Enter your total allowable itemized deductions from your >993 Ocneduie A, line 26.............................................................. Filing status on your 1993 Form 1040 _ Single _ Mai nod fifing jointly or qualifying wxfcw(er) _ Married filing separately _Married filing separately arid your spouse itemized deductions । tin ad of Household Note: if the fimg status on your 1993 Form <<M was mamed filin'} separate у and yot r spouse temized deductions in 1993, shin fines 3 throu^r 5 and enter the amount from fine 2 or. une 6. 3 Enter Йк amount shown below tor the filing status claimed on your 1993 Form tiMtn • uingleenter 13,700.................. ,....................... • Married filing jointly or qualifying wrdowfer), enter $6,200 . • Mamed filing separately, enter $3,100................... • Head of household, enter $5,450 ............ .___________
Form 1040 Social Security Income Worksheet 1994 _______Une 20_______________________** Keep far your records Name(s) shown on return Socrai Security Number Taxpayer Spouse A Enter the total amount from Box 5 of aS your Forms SSA-1099 ............. 8 Emer the total amount from Box 5 of aS your Forms RRB-1099 .... 1 Add amounts from line A and line 8 2 Enter one-hall of line 1.......................................................... 3 Add the amounts on Form 1040, lines 7.8a (before U.S. Mings bond ..He rest exclusion). 8b. 9 through 14, 15b, I6b< 17 through 19, aid line 21 .................... 4 Foreign earned income exclusion, foreign housing exclusion exclusion of income from U.S. possessions, or exclusions of income from Puerto Rico by bona frde residents of Puerto Rko that you claimed .... 5 Add lines 2, 3, and 4 .............................................................. 6 Amount from Form 1040, lines 23 though 29. (Hus any Write-in amounts on line 30 (other than foreign housing deoumion) .. .. 7 Subtract line 6 from line 5 .................... 8 Enter $25,1X10 ($32.000 if mamed filing jointly; $0 if man «I filing s-roarUeiy and you lived with your spouse at any time in 1994). .. 9 Subtract line 8 from line 7. If zero or less, entpr -0................... .......... ft Bne 9 Is aero, stop: пси ie of your sor-al security ter»f-ts ere ia table Do not enter any amounts on Form 1040. lain 20a or 20b or Form 134UA, linns 13e or *3i> Buf rf you are married filing separately and you lived apart from your spoi ®e tar all of 1994, enter -0- on Form 1040. line 20b or Form 1040A hoe 13b. 8e sire to enter ЧГ to the left of Form '-CteO. Une 20b or Form lOeJA, line 13b. И line 9 is more than zeta. go to line 10. 10 Enter 99,000 ($12 000 if married filing jointly; $0 it marnec. filing separately and you liveo with your х|тлве ar any nme in 1994 ................ 11 Subtract line 10 from line 9. If Zero or less, enter -0- _ ___________________ . _____ 12 Enter toe smelter of lino 9 or line 10............................................................. 13 Enter one-half of line 12.......................................................................... 14 Enter the smaller of line 2 or line 13.............................................. ____________ 15 Multiply line 11 fry 85% (.85) If line 11 is zero, enter -0-....................................... 18 Add lines 14 and 15................................................................................ 17 Multiply hr» 1 by 85% (.85)...................................................... ................. 18 Taxable social security benefits. Enter the smaller of line 16 or line 17.... ..................... • Enter the amount from line 1 on Form 1040. line 20a, or Form 1040A. line 13a. • Enter the amounl from line 18 on Form 1040, line 2Db or Form 040A. line 13b.
Form 1040 Self-Employed Health insurance Deduction Worksheet 1994 Une 26 »• Keep for your records Name Social Socunty Numbw Note If you have more Iran one source of income sublet t to self-employment Is x. or you file Form 2565, enter > our payments on the first Une of this worksheet, then UM the worksheet tn Publlcaltoo 535 to compute your deduction, end override line 8 below. A Enter total payments made for health insurance coverage for you, your spouse, and dependents.................................................. A В Medical care insurance expense from Schedule К-1 Pi»w»i ihp > e ‘ nhe- s .. в 1 Total payments made for health insurance coverage for you, your spouse, and dependents............................................................... 1 2 Percent age used to figure 9» deduction . ................................. 2 X .25 3 Multpl/ Ime 1 by the perpenrage on line 2 .......................... 3 C Net profit from your trade or nusiness ........................................... C 0 If you are a statutory employee end are considered s**f-e>np)ov«: for the purposes of the be»uh insurance dedt clioo, enter yoir r»i profit from the business........................................................ t> E Enter you wages wr. an S Corporation >n which you are a m&e than 2% sherehokter ...............E ♦ net profit and any othei earr«w income wn wsuwss under wnicr the insura ice plan is establish»», mirxn any deductions you claim on Form ЧКО, lines 25 4 27 .. 4 5 Sen-oirtutoyed health Insurance oeouUlon, Enter the «natter or fine 3 tx lute 4 here and on Form ItWJ, line 2fi. (Do not incluoe this amount m figuring any irwdival expel йе deduction on buheduiv A (Form 1040)).............................. 5
Standard Deduction Worksheet for Dependents 1994 Use ibis worksheet only И someone can ciaim you as a dependent ___________________________________*• Keep tor your records te«(s) «town on return_____________Social Security Number 1 Enter your tamed income (defined below}. If none, enter -0- 1 2 Minimum amount . 2 3 Enter the larger of line or line 2 3 4 Enter on hne 4 the amount shown below for you filing status: ♦Single, enter $3,800 ♦Married filing separately, ante? $3J75 •Married filing jointly or Qualified — wictow{*r) enter $6,350 ♦htead of Household, enter $5,600 4 5 Standard deduction. a Enter Die emalet of line 3 or line 4. if under 65 and net blind, slot here and an*w ths acnourrr on Form |П40, fine 34; or Form IU4OA, line 19 Otherwise, pc to fir» Sb ...............................................5a__________________ b if 65 or older or blind, multiply SyoO (1750 if married filing lointly Oi separately, or qualified widow(er)) by the number on Form 1040, lire 33a, or Form 1040A, line 18a. 5b c Add lines 5e and 5b. Enter the total here and on Form I Ott. line 34; or Fa m l040«. line'9. ..................................................................... Sc Eemad Income imdudes wages. talerau, tips, professional was. ano other cwimnsafiori revived tor pecs snal services you perfamed Л also includes anv amount received as a sc! warship that you must include in your r-xome. Generally, your eariied »kx> >>e is the tutai oi the arrwjn'tty you reported on form 1040, hues ?, 12. and 18, minus the amoun', d any; on line 25; or on Form IMu, line 7.
Schedule А Une 29 №ama($) shown on return Itemized Deductions Worksheet »• Keep for уснл- records 1994 i Social Security Nurrfcer Add the amounts on Schedule A, lines 4, 9. I4, 18, I9, 26, 27 avd 28 2 Add the amounts on Schedule A. tines 4. 13. and 19. plus any ganulng losses included on line 28 ......................................... 2 Cauttom Be sure your total gambling losses are identified on tne Moiceilenecua ftemoed Deductions Statement. 3 Subtract line 2 from line 1. If the resist Is zero, Stop Here; enter the amount from line 1 above on Schedule A, line 29 ................. 3 4 Multiply line 3 above by 80% (.80} 4 5 Enter the ainomt from Form 1040, line 32 5 6 Enter $111,800 ($55,900 if married filing sejerately) 8 7 Subtract line b from line 5. H the result is zero or lass, Stop Here; enter the ar ount from ime 1 above on Schack4a A, line 29....................................... 7 ... ............ 8 Mutfipfr line 7 above oy 3% (.03) .................... В 9 Enter the *m«8»r at line 4 or line 8 ... ........ 9 18 Total Itemized deoucdwit. Subtract line 9 from line I. Enter the resist ne, « a.x) on Schedule A, line 29 . .... . 10
Индивидуальные пенсионные счета Individual Retirement Account Worksheet 1 1994 * Keep for your records__________________________________ Namais) shown on return ' Isooisl Security Number (a) Your IRA (b) Working Spouse's IRA 1 Enter IRA contributions made for 1994, but do not enter more than $2,000 .................................................. 2 Enter you wages and other earned income 3 Enter the smaller of line 1 or line 2. Enter on Form 104' line 23a or 23o (Form 1O40A, line 15a or 15b). 4 5 6 7 8 Nonworking spouse's IRA Enter the smaller ot line 2 or $2.250. Enter the amount from line 3 Subtract l»r>e 5 from line 4 .. ................. Enter IRA contributions made for 1994 for foe nonworking spouse but not more than $2,000 Enter the smaller of Ifoe 6 or line 7. Enter on Form 1040, line 23a or 23b ( Form 1040A, line 15a or 15b).............. Г
Список литературы AFIF90 Afifi, Е. Н., and White, L. J. “Testing for Linear Errors in Nonlinear computer Programs.” Technical Report CES-90-03, Department of Computer Science, Case Western Reserve University, March 1990. AFIF92 Afifi, E. H., White, L. J., and Zeil, S. J. “Testing for Linear Errors in Nonlinear Computer Programs.” Proceedings of the 14th International Conference on Software Engineeing, Australia, pp. 81-91. ALLE72 Alien, F. E., and Cocke, J. “Graph Theoretic Constructs for Program Control Flow Analysis.” IBM Research Report RC3923. Yorktown Heights, N Y; TJ. Watson Research Center, 1972. ANDE79 Anderson, R. B. “Proving Programs Correct”. New York: John Wiley & Sons, 1979. ANDR81 Andrews, D.M., and Benson, J. P. “An Automated Program Testing Method and Its Implementation.” Fifth International Conference on Software Engineering, San Diego, CA, March 9-12, 1981. Use of assertions in testing. ANSI94 ANSI/IEEE Standard PI 044-1994. “Standard Classification for Software Anomalies”. New York: American National Standards Institute, 1994. AVRI93 Avritzer, Alberto, and Larson, Brian. “Load Testing Software Using Deterministic State Testing.” Proceedings of the 1993 International Symposium on Software Testing and Analysis, Cambridge, MA June 28-30, 1993. pp. 82-88. ВАВЕ94 Baber, Robert L. “Proofs of Correctness.” In MARC94, pp. 925-930. ВАСК59 Backus, J. “The Syntax and the Semantics of the Proposed International Algebraic Language.” Proceedings of the ACM-GAMM Conference. Paris, France: Information Processing, 1959.
BALC89 BARN72 BASI87 BAUE79 BEIZ84 BEIZ90 BE1Z96 BELF76 BEND70 Balcer, Marc J., Hasling, William M„ and Ostrand, Thomas J. “Automatic Generation of Test Scripts from Formal Test Specifications.” Proceedings of the ACM SIGSOFT ‘89. Third Symposium on Software Testing, Analysis, and Verification. Key West, FL, December 13-15, 1989. pp. 210-218. Automatic behavioral test generation based on the proprietary TSL specification language. Barnes, В. H. “A Programmer’s View of Automata.” Computing Surveys 4 (1972): 222-239. Introduction to state graphs and related automata theory topics from a software-application perspective. Basili, V. R., and Selby, R.W. “Comparing the Effectiveness of Software Testing Strategies.” IEEE Transactions on Software Engineering 13, #12 (1987): 1278-1296. A (rare) attempted controlled experiment to explore the relative effectiveness of behavioral versus structural testing, coverage metrics, professional versus student prog’-ammers. Bauer, J. A., and Finger, A. В “Test Plan Generation Using Formal Grammars.” Fourth International Conference on Software Engineering, Munich, Germany, September 17-19, 1979. Use of state-graph model for automated test case generation. Application to telephony. Beizer, B. “Software System Testing and Quality Assurance.” New York: Van Nostrand Remhold, 1984. Test and QA management, integration testing, system testing. Organization of testing, behavioral testing, formal-acceptance testing, stress testing, software reliability, bug-prediction methods, software metrics, test teams, adversary teams, design reviews, walkthroughs, etc. Beizer, B. “Software Testing Techniques”, 2nd ed. New York: Van Nostrand Reinhold, 1990. The testing book to read after this one. Structural test techniques, behavioral test techniques in more detail, interaction of software design and testability, algorithms for tool builders. Beizer, B. “Integration and System Testing (in preparation).” Integration testing strategies, reintegration, system testing techniques. Application of test techniques to system testing. Black-Box Testing is a prerequisite. Belford, P. C., and Taylor, D. S. “Specification Verification — A Key to Improving Software Reliability.” In Proceedings of the PIB Symposium on Computer Software Engineering. New York: Polytechnic Institute of New York, 1976. Verification of specifications, use of specification languages, and related subjects. Bender, R. A., and Pottorff, E. L. “Basic Testing: A Data Flow Analysis Technique”. IBM System Development Division,
BEND85 BERA94 BERL94 BISW87 ВОЕН81 ВОЕН86 BOWD77 BRIT85 BRZ062 BRZ063 BURK88 BUTL89 Poughkeepsie Laboratory, TR-00.2108, October 9, 1970. Earliest known description of data-flow testing. Bender, R. A., and Becker, P. “Code Analysis”. Larkspur, CA: Bender and Associates, P.O. Box 849, 94939. Proprietary software development and test methodology that features use of data flow testing techniques. Berard, Edward V. “Object Oriented Design.” In MARC94, pp. 721-729. Berlack, H. Ronald. “Configuration Management.” In MARC94, pp. 180-206. Detailed overview of software configuration control and management practices. Biswas, S., and Rajaraman, V. “An Algorithm to Decide Feasibility of Linear Integer Constraints Occurring in Decision Tables.” IEEE Transactions on Software Engineering SE-13, #12 (December 1987), pp. 1340-1347. Boehm, Barry W. “Software Engineering Economics”. Englewood Cliffs, NJ: Prentice-Hall, 1981. Source book for all aspects of software economics. Boehm, Barry W. “A Spiral Model of Software Development and Enhancements.” ACM Software Engineering Notes 11, (4), (1986), pp. 22-42. Bowditch, N. “American Practical Navigator”, 70th ed. Washington, DC: Defense Mapping Agency Hydrographic Center, 1977. The oldest book in continuous publication except for the Bible. What our discipline should strive to be when it grows up. Britcher, R. H., and Gafmey, J. E. "Reliable Size Estimates for Software Systems Decomposed as State Machines.” Ninth International Computer Software and Applications Conference, Chicago, IL, October 9-11, 1985. Representation of program as finite-state machine relates state-machine size to program size. Brzozowski, J. A. “A Survey of Regular Expressions and Their Application.” IRE Transactions on Electronic Computers 11 (1962), pp. 324-335. Survey of regular expression theory and relation to finite-state machines. Brzozowski, J. A., and McCluskey, E. J., Jr. “Signal Flow Graph Techniques for Sequential Circuit State Diagrams.” IEEE Transactions on Electronic Computers 12 (1963), pp. 67-76. Basicpaper that applies flow graphs to regular expressions and state-graphs of finite-state automata. Burke, R. @Black-Box Regression Testing — An Automated Approach.” Fifth International Conference on Testing Computer Software, Washington, DC, June 13-16, 1988. Butler, R. W., Mejia, J. D., Brooks, P. A., and Hewson, J. E. “Automated Testing for Real-Time Systems.” Sixth International
CHEN78 CHOW78 CHOW88 CLAR76 CLAR82 CLAR89 СОНЕ78 CONK89 C00PS1 CROS92 DAIC93 Conference on Testing Computer Software, Washington, DC, May 22-25,1989. Chen, W. T, Ho, J. P., and Wen, С. H. “Dynamic Validation of Programs Using Assertion Checking Facilities.” Second Computer Software and Applications Conference, Chicago, IL, November 1978. Chow, T. S. “Testing Software Design Modeled by Finite State Machines.” IEEE Transactions on Software Engineering 4 (1978), pp. 78-186. Testing software modeled by state graphs with examples from telephony. Categorizes types of state-graph errors and shows relation between type of coverage and the kind of errors that can and can’t be caught. Chow, С. H., and Lam, S. S. “Prospec: An Interactive Programming Environment for Designing and Verifying Communication Protocols.” IEEE Transactions on Software Engineering 14 (1988), pp. 327-338. Clarke, Lori A. “A System to Generate Test Data and Symbolically Execute Programs.” IEEE Transactions on Software Engineering 2 (1976), pp. 215 -222. Although aimed at structural testing, the method and tools could be applied just as easily to behavioral control flow and data flow models. Clarke, Lori A., Hassel, J., and Richardson, D. J. “A Close Look at Domain Testing.” IEEE Transactions on Software Engineering 8 (1982), pp. 380-390. Good survey and critique; exposition of error types and what does and doesn’t work to catch them and why. Clarke, Lori A., Podgurski. Andy, Richardson, Debra J„ and Zeil, Steven J. “A Formal Evaluation of Data Flow Path Selection Criteria.” IEEE Transactions on Software Engineering 15(1989), pp. 1318-1332. Cohen, E. I. “A Finite Domain-Testing Strategy for Computer Program Testing.” Ph. D. diss., Ohio State University, June 1978. Conklin, J. “Automated Repetitive Testing.” Sixth International Conference on Testing Computer Software, Washington, DC, May 22-25, 1989. Cooper, Robert B. “Introduction to Queuing Theory”. New York: Elsevier North Holland, 1981. “CrossTalk Communications.” CASL Programmer Guide. Rosswell, GA: Digital Communications Associates, 1992. Daich, Greg, and Price, Gordon. “Test Preparation Execution, in Evaluation Software Technologies Report”. Software Technology Support Center, Hill AFB, Ogden, UT. Customer Service 801-777-7703. Free periodical guide to test tools and technology approved for use in U. S. government. Also, Reengineering Tools Report, Source Code Static Analysis Technologies Report, vols. 1 and 2.
DAVI88 DEON74 EBER94 ELME73 FAGA76 FENT91 FRAN85 FRAN88 FREE88 FSTC83 FUJI94 FURG89 GERH88 Davis, А. М. “A Comparison of Techniques for the Specification of External System Behavior.” Communications of the ACM 31, #9(1988), pp. 1098-1115. Survey of state graphs, state tables, decision tables, decision trees, program design languages, Petri nets, requirement languages, and specification languages in developing requirements and tests from them. Deo, N. “Graph Theory with Applications to Engineering and Computer Science". Englewood Cliffs, NJ: Prentice-Hall, 1974. Ebert, Jurgen and Engels, Gregor. “Design Representations.” In MARC94, pp. 382-394. Survey of popular design models and representations, all of which can be used as a basis for test design. Elmendorf, W. R. “Cause-Effect Graphs in Functional Testing”. TR-00.2487, IBM Systems Development Division, Poughkeepsie, NY, 1973. Fagan, M. E. “Design and Code Inspections to Reduce Errors in Program Development”. IBM Systems Journal 3 (1976) pp: 182-211. Still one of the best expositions on inspections ever written. Fenton, Norman E. “Software Metrics: A Rigorous Approach”. London: Chapman and Hail, 1991 A rigorous but very accessible book on software metrics, suitable for a first course. Franki, P. S., Weiss, S. N. and Weyuker, EJ. “Asset — A System to Select and Evaluate Tests.” Proceedings of the IEEE Conference on Software Tools (April 1985), pp. 72-79. Franki, P. G., and Weyuker, E. J. “An Applicable Family of Data Flow Testing Criteria.” IEEE Transactions on Software Engineering 14, #10 (1988), pp. 1483-1498. Freeman, P. A., and Hunt, H. S. “Software Quality Improvement Through Automated Testing.” Fifth International Conference on Testing Computer Software, Washington, DC, June 13-16, 1988. Federal Software Testing Center. “Software Tools Survey”. Office of Software Development report #OSD/FSTC-83/015,1983. Survey of 100 software development tools, language, source. Fujii, Roger U. “Independent Verification and Validation.” In MARC94, pp. 568-572. What an independent test group is all about. Furgerson, Donald F., Coutu, John P., Reinemann, Jeffrey K., and Novakovich, Michael R. “Automated Testing of a Real-Time Microprocessor Operating System.” Sixth International Conference on Testing Computer Software, Washington, DC, May 23-25, 1989. Description of application of CrossTalk CASL scripting language to test script design and to construction of a testing environment. Gerhart, Susan L. “A Broad Spectrum TooEset for Upstream Testing, Verification, and Analysis.” Second Workshop on
GIBB94 GILB93 GOOD75 GRAD87 GRAD92 GRAH91 GRAH93 GRAH94 HAML88 HAML94 HANF70 HANT76 HARR89 Software Testing, Verification, and Analysis, Banff, Canada, July 19-21, 1988. Gibbs, Wayt. “Software’s Chronic Crisis.” Scientific American, 71, #3(1994), pp. 86-95. Gilb, Tom, and Graham, Dorothy. “Software Inspections”. Menio Park, CA: Addison-Wesley, 1993. As good and as readable text on inspections as you’re likely to find. Goodenough, J. B., and Gerhart, S. A. “Toward a Theory of Test Data Selection.” IEEE Transactions on Software Engineering 1 (1975), pp. 156-173. The beginning of testing theory; historical interest. Grady, Robert B„ and Caswell, D. L. “Software Metrics: Establishing a Company-Wide Program”. Englewood Cliffs, NJ; Prentice-Hall, 1987. A practical guide to implementing a total metrics program based cm expeviewce m a swppoWNe, sophisticated, software devefopment ovgamzatkm, Grady, Robert B. “Practical Software Metrics for Project Management and Process Improvement”. Englewood Cliffs, NJ'. Prentice-Hall, 1992. Yet another practical guide to metrics in an industrial setting, courtesy of Hewlett-Packard. Graham, Dorothy R. “Software Testing Tools: A New Classification Scheme.” Journal of Software Testing, Verification, and Reliability 1, #3 (October-December 1991) pp. 17-34. An overview and rational taxonomy for test tools. Graham, Dorothy R„ and Herzlich, Paul. “CAST Report: Computer Aided Software Testing”. London: Cambridge Market Intelligence, 1993. Periodical report on test tools for mostly European platforms. Graham, Dorothy R. “Testing” In MARC94, pp. 1330-1353. Testing with a software development process perspective. Hamlet, R., and Taylor, R “Partition Testing Does Not Inspire Confidence.” Second Workshop on Software Testing, Verification, and Analysis, Banff, Canada, July 19-21, 1988. Shows that partition testing methods cannot be used to obtain statistically meaningful software reliability measures. Hamlet, Richard. “Random Testing.” In MARC94, pp. 970-978. Hanford, К. V. “Automatic Generation of Test Cases.” IBM System Journal 9 (1979), pp. 242-257 UseofBNF to generate syntactically valid test cases for testing a PL/I compiler. Hantier, S. A., and King, J. C. “An Introduction to Proving the Correctness of Programs.” ACM Computing Surveys 8, 3 (1976), pp. 331-353. Harrold, M. J., and Sofia, M. L. “An Incremental Data Flow Testing Tool.” Sixth International Conference on Testing Computer Software, Washington, DC, May 22-25, 1989.
HEND89 HERA88 HERM76 HOLT87 HOLZ87 HORG92 HORG94 HOWD76 HOWD80 HOWD86 HOWD87 HOWD89 Henderson, В. М. “Big Brother — Automated Test Controller.” Sixth International Conference on Testing Computer Software, Washington, DC, May 22-25, 1989. Herath, J., Yamaguchi, Y, Saito, N., and Yuba, T. “Dataflow Computing Models, Languages, and Machines for Intelligence Computations.” IEEE Transactions on Software Engineering 14, 12 (1988), pp. 1805-1828. Although the paper is aimed at intelligence processing, the overview and tutorial is one of the best around. Herman, P. M. “A Data Flow Analysis Approach to Program Testing.” Australian Computer Journal (November 1976), pp. 92-96. Earliest known published discussion of heuristic data flow testing. Holt, D. “A General Purpose Driver for UNIX.” Fourth International Conference on Testing Computer Software, Bethesda,MDJune 15-18, 1987. Holzman, G. J. “Automated Protocol Validation in Argos: Assertion Proving and Scatter Searching.” IEEE Transactions on Software Engineering 13 (1987), pp. 683-696. Experience in automatically generated state machine based testing cases as applied to protocol verification. Application and strategies for systems with on the order of 1024 states. Horgan, J. R„ and London, S. A. “A Dataflow Coverage Testing Tool for C.” Proceedings Symposium on Assesment of Quality Software Developement Tools. Los Alamitos, СЛ: IEEE CS Press, 1992, pp. 2-10. Description of the ATAC public domain C dataflow test tool. Horgan, J. R., London, S A., and Lyu, M. R. “Achieving Software Quality with Testing Coverage Measures.” IEEE Computer 7, #9 (Sept. 1994), pp. 60-70. Howden, W. E. “Reliability of the Path Analysis Testing Strategy.” IEEE Transactions on Software Engineering 2 (1976), pp. 208-215. Proof that the automatic generation of a finite test set that is sufficient to test a routine is not a computable problem. Formal definition of computation error, path error, and other kinds of errors. Howden, W. E. “An Evaluation of the Effectiveness of Symbolic Testing.” IEEE Transactions on Software Engineering 6 (1980), pp. 162-169. Howden, William E. “A Functional Approach to Program Testing and Analysis.” IEEE Transactions on Software Engineering 12 (1986), pp. 997-1005. Howden, William E. “Functional Program Testing and Analysis”. New York: McGraw-Hill, 1987. Howden, William E. “Validating Programs Without Specifications.” Proceedings of the ACM SIGSOFT ‘89, Third
IDEI94 IEEE94 JENG89 JENG94 KAVI87 КЕММ85 KOLM88 KORE85 KORE88 KRAU73 LASK90 LAYC92 LEMP89 Symposium on Software Testing, Analysis, and Verification.Key West, FL, December 13-15, 1989, pp. 2-9. Exposition of error-based testing. IDE, Inc. “Stp/T User’s Guide”. Iselin, NJ: Interactive Development Environments, 1994. “IEEE Software Engineering Standards”. New York: IEEE, 1994. Collection of ANSI/IEEE standards on software engineering. Jeng, B., and Weyuker, EJ. “Seme Observations on Partition Testing.” Proceedings of the ACM SIGSOFT ‘89, Third Symposium on Software Testing, Analysis, and Verification. Key West, FL, December 13—15, 1989. Jeng, В. C„ and Weyuker, E. J. “A Simplified Domain-Testing Strategy.” ACM Transactions on Software Engineering and Methodology 3 July 1994), pp. 254-270. Kavi, К. M., Buckles, B. R, and Bhat, N. U. “Isomorphism Between Petri Nets and Dataflow Graphs.” IEEE Transactions on Software Engineering 13 (1987), pp. 1127-1134. Relation between Petri Nets and data-flow models. Kemmerer, R. A. “Testing Formal Specifications to Detect Design Errors.” IEEE Transactions on Software Engineering 11, #1 (1985), pp. 32-43. Kolman, B. “Introductory Linear Algebra with Applications”, 4th ed. New York: Macmillan and Company, 1988. Introductory Text used in computer sciences curricula, Korel, Bogdan, and Laski, Janusz, “A Tool for Data Flow Oriented Program Testing ” Second Conference on Software Development Tools, Techniques, and Alternatives, San Francisco, CA, December 2-5, 1985. Korel, Bogdan, and Laski, Janusz. “STAD — A System for Testing and Debugging: User Perspective.” Second Workshop on Software Testing, Verification, and Analysis. Banff, Canada, July 19-21, 1988, pp. 13-20. Krause, K. W, Smith, R. W, and Goodwin, M. A. “Optimal Software Test Planning Through Automated Network Analysis.” IEEE Symposium on Computer Software Reliability, 1973. Early example of path testing, graph models, coverage, and automated generation of paths. Laski, J. “Data Flow Testing in STAD.” Journal for Systems and Software 12 (1990), pp. 3—14. Laycock, Gilbert. “Formal Specification and Testing: A Case Study.” Journal of Software Testing. Verification, and Reliability 2, #1 (May 1992), pp. 7-23. Category-partition model and test generation based on the Z specification language. Lemppenau, W. W. “Hybrid Load and Behavioral Testing of SPC-PABX Software for Analog or Digital Subscribers and
MARC94 MASO90 МАТТ88 MCNA60 MEAL55 MILL66 MILL75 MILL78 MILL86 MOLL93 MOOR56 MORE90 MURA89 MUSA90 Trunk Lines.” Sixth International Conference on Testing Computer Software, Washington, DC, May 22-25, 1989. Marciniak, John (editor-in-chief). Encyclopedia of Software Engineering. New York: John Wiley & Sons, 1994. The essential reference book that no serious software engineer or aspirant thereto should be without. Any technical term or concept used in this book that you do not know you can probably learn from MARC94. Get the CD-ROM version when it comes out. Mason, T, and Brown, D. Lex and yacc. Sebastapol, CA: O’Reilly and Associates, 1990. Matthews, R. S., Muralidhar, К. H., and Sparks, S. “MAP 2.1 Conformance Testing Tool.” IEEE Transactions on Software Engineering 14, #3 (1988), pp. 363-374. McNaughton, R., and Yamada, H. “Regular Expressions and State Graphs for Automata.” IRE Transactions on Electronic Computers EC-9 (I960), pp. 39-17. Survey ol the theory of regular expressions as applied to finite state automata. Proof of fundamental theorems. Mealy, G. H. “A Method for Synthesizing Sequential Circuits." Bell System Technical Journal 34 (1955), pp. 1045-1079 Miller R. E. “Switching Theory”. New York: John Wiley & Sons, 1966. Basic reference on switching and automata theory. Miller, E. E, and Melton, R. A. “Automated Generation of Test Case Data Sets.” International Conference on Reliable Software, Los Angeles, CA, April 1975. Miller, E. E, and Howden, W. E. eds. “Tutorial: Software Testing and Validation Techniques”, 2nd ed. New York: IEEE Computer Society, 1981. A bargain resource for pre-1981 literature; huge bibliography up to and including 1981. Miller, E. F. “Mechanizing Software Testing.” TOCG Meeting, Westlake Village, CA, April 15, 1986. San Francisco: Software Research Associates. Moller, К. H„ and Paulish, D. J. “Software Metrics”. London: Chapman and Hall, 1993. Metrics from an industrial viewpoint. Moore, E. F. “Gedanken Experiments on Sequential Machines.” In Automata Studies. Annals of Mathematical Studies #34. Princeton, NJ: Princeton University Press, 1956. Morell, Larry J. “A Theory of Fault-Based Testing.” IEEE Transactions on Software Engineering 16, #8 (August 1990), pp. 844-857. Murata, T. “Petri Nets: Properties, Analysis And Applications.” Proceedings of the IEEE 77, #4 (1989), pp. 541-580. In-depth tutorial, huge bibliography. Musa, John D., lannino, Anthony, and Okumoto, Kazuhira. “Software Reliability: Professional Edition”. New York: McGraw-Hill, 1990.
MYER79 Myers, G. J. The Art of Software Testing. New York: John Wiley & Sons, 1979. A golden oldie. NAFT72 Naftaly, S. M„ and Cohen, M. C. “Test Data Generators and Debugging Systems... Workable Quality Control.” Data Processing Digest 18 (1972). Survey of automatic test data generation tools. NOMU87 Nomura, T. “Use of Software Engineering Tools in Japan.” Ninth International Conference on Software Engineering, Monterey, CA, March 30 — April 2, 1987, Survey of 200 Japanese software development groups rates test tools as having the highest productivity return; ahead of a standard process, programming and design tools, and reviews. NORT94 Northrup, Linda M. “Object-Oriented Development.” In MARC94, pp. 729-737. NTAF88 Ntafos, Simeon C. “A Comparison of Some Structural Testing Strategies.” IEEE Transactions on Software Engineering 14, # 6 (June 1988), pp. 868-874. Excellent survey of structural test techniques. ONOM87 Onoma, A. K„ Yamura, T, and Kobayashi, Y. “Practical Approaches to Domain Testing: Improvement and Generalization.” Proceedings of the Computer Software and Applications Conference, Tokyo, Japan, October 7-9, 1987, pp. 291-297. OSTR86 Ostrand, T. J., Sigal, R„ and Weyuker, E. “Design for a Tool to Manage Specification-Based Testing.” Workshop on Software Testing, Banff, Canada, July 15-17, 1986. OSTR88 Ostrand, T. J., and Baker, M. J. “The Category-Partition Method for Specifying and Generating Functional Tests.” Communications of the ACM 31, #6 (1988), pp. 676-686. OSTR91 Ostrand, Thomas J., and Weyuker, Elaine J. “Data Flow-Based Test Adequacy Analysis for Languages with Pointers.” ACM Sigsoft Symposium on Software Testing, Analysis, and Verification, October 8-10, 1991, Victoria, BC, Canada. OSTR94 Ostrand, Thomas J. “Categories of Testing.” In MARC94, pp. 90-93. Overview of different types of testing and where and how used. PANZ78 Panzl, D. J. “Automatic Software Test Drivers.” IEEE Computer 11(1978), pp. 44-50. PATR88 Patrick, D. P. “Certification of Automated Test Suites with Embedded Software.” National Institute for Software and Productivity Conference, Washington, DC, April 20-22, 1988. PERE85 Perera, L. A., and White, L. J. “Selecting Test Data For the Domain Testing Strategy.” Technical report TR-85-5, Department of Computer Science, University of Alberta, Edmonton, Alberta, Canada, 1985.
PERE86 РЕТЕ76 РЕТЕ81 PIGO94 POST94 POWE82 RAPP82 RAPP85 RICH81 RICH85 RICH89 ROPE93 Perelmuter, I. М. “Directions of Automation in Software Testing.” Third Conference on Testing Computer Software, Washington, DC, September 29 — October 1, 1986. Peters, L. J., and Tripp, L. L. “Software Design Representation Schemes.” PIB Symposium on Computer Software Reliability, Polytechnic Institute of New York, April 1976. Survey of software models, including HIPO charts, activity charts, structure charts, control graphs, decision tables, flowcharts, transaction diagrams, and others. Petersen, J. L. “Petri Net Theory and the Modeling of Systems”. Englewood Cliffs, NJ: Prentice-Hall, 1981. Basic text on Petri nets. Pigoski, Thomas M. “Maintenance.” In M ARC94, pp. 619-636. Poston, Robert M. “Test Generators.” In MARC94, pp. 1327-1330. Powell, P. B. ed. “Software Validation, Verification, and Testing Techniques and Tool Reference Guide”. National Bureau of Standards Special Publication 500 -93, 1982. Survey of testing, verification, validation, tools, and techniques with comments on effectiveness and supporting and resources needed for each. Rapps, S., and Weyuker, E. J. “Data Flow Analysis Techniques for Test Data Selection.” Sixth International Conference on Software Engineering, Tokyo, Japan, September 13-16, Long Beach, CA: 1982, pp. 272-278. Rapps, S., and Weyuker, E. J. “Selecting Software Test Data Using Data Flow Information.” IEEE Transactions on Software Engineering (1985), pp. 367-375. Richardson, D. J., and Clarke, L. A. “A Partition Analysis Method to Increase Program Reliability.” Fifth International Conference on Software Engineering, San Diego, CA, March 9-12, 1981. Partition analysis testing; behavioral/structural hybrid based on domain testing. Richardson, D. J., and Clarke, L. A. “Partition Analysis: A Method Combining Testing and Verification.” IEEE Transactions on Software Engineering 11 (1985), pp. 1477-1490. Early look at behavioral domain testing. Richardson, Debra J., O’Malley, O. and Tittle, Cindy. “Approaches to Specification-Based Testing.” Proceedings of the ACM SIGSOFT ‘89, Third Symposium on Software Testing, Analysis, and Verification. Key West, FL, December 13-15, New York, NY: 1989, pp. 86-96. Behavioral testing based on formal specification languages, Anna and Larch. Roper, Marc, and Rashid, Ab Bin Ab Rahim. “Software Testing Using Analysis and Design Based Techniques.” Journal of Software Testing, Verification, and Reliability 3, #3-4
ROYC70 RUGG79 SARI87 SCAC94 SCHI69 SCHL70 SIDH89 SNEE86 SOFT88 SQET94 STAK89 THEV93 (September-December 1993), pp. 166-179. Behavioral data flow models used as a basis for test design. Royce, W. W. “Managing the Development of Large Software Systems.” Proceedings IEEE WESCON (August 1970), pp. 1-9. Ruggiero, W., Estrin, G., Fenchel, R., Razouk, R„ Schwabe, D., and Vernon, M. “Analysis of Data Flow Models Using the Sara Graph Model of Behavior.” Proceedings of the 1979 National Computer Conference. Montvale, NJ: AFIPS Press, 1979. A more elaborate data flow behavioral model than presented here. Sarikaya, Behcet, Bochmann, Gregor V., and Cerny, Eduard. “A Test Design Methodology for Protocol Testing.” IEEE Transactions on Software Engineering, SE-13, #5 (May 1987), pp. 518-531. Scachi, Walt. “Process Maturity Models.” In MARC94, pp. 851-869. Schiller, H. “Using MEMMAP to Measure the Extent of Program Testing.” IBM Systems Development Division, Poughkeepsie, NY, Report TR 00 1836. February 10, 1969. Description of the use of an early software statement/branch coverage analyzer. Schlender, Paul, J. “Path Analysis Techniques”. Memo, IBM System Development Division, Poughkeepsie, NY, April 27, 1970. Early discussion of data flow testing (all definitions); notes (without proof) that branch coverage is included in all definitions Sidhu, Deepinder P., and Leung, Tink-Kau. “Formal Methods for Protocol Testing: A Detailed Study.” IEEE Transactions on Software Engineering 15, #4 (April 1989), pp. 413-423. Automatic test generation for protocol testing f~om finite-state model. Sneed, H. M. “Data Coverage Measurement in Program Testing.” Workshop on Software Testing, Banff, Canada, July 15-17, Washington, DC: 1986, pp. 34-40. Reports experience with use of data-flow coverage metrics; tools, comparison of effectiveness with control-flow coverage. Software Research, Inc. “SPECTEST™ Description, METAT-EST™ Description”. San Francisco, CA: Author, 1988. Software Quality Engineering. Tools Guide. Jacksonville, FL: Author, 1994. Periodical tools guide specific to software testing. Staknis, M.E. “The Use of Software Prototypes in Software Testing.” Sixth International Conference on Testing Computer Software, Washington, DC, May 22-25, 1989. Thevenod-Fosse, Pascale, and Waeselynck, Helene. “STATE-MATE Applied to Statistical Software Testing.” Proceedings of the 1993 International Symposium on Software Testing and Analysis. Cambridge, MA, New York, NY: ACM Press, June 28-30, 1993, pp. 99-109.
TRIP88 TSAI90 VOGE80 VOGE93 WALL94 WARN64 WEIN90 WEIS81 WEIS84 WEIS85 WEIS91 WEYU90 WEYU94 WHIT78 Tripp, Leonard L. “A Survey of Graphical Notations for Program Design — An Update.” ACM SIGSOFT, Software Engineering Notes 13, #4 (October 1988), pp. 39-44. Concise survey. Tsai, W.T, Volovik, Dmitry, and Keefe, Thomas, F. “Automated Test Case Generation for Programs Specified by Relational Algebra Queries.” IEEE Transactions on Software Engineering 16, #3 (March 1990), pp. 316-324. Automated test generation based on domain models. Voges, U„ Gmeiner, L., and von Mayrhauser, A. A. “Sadat — An Automated Test Tool.” IEEE Transactions on Software Engineering 6, #3 (May 1980), pp. 286-290. Vogel, Peter A. “An Integrated General Purpose Automated Test Environment.” Proceedings of the 1993 International Symposium on Software Testing and Analysis. Cambridge, MA, June 28-30, New York, NY’ ACM Press, 1993, pp. 61-69. Wallace, Dolores R. “Verification and Validation.” In MARC94, pp.1410-1433. Warner, C. D„ Jr. “Evaluation of Program Testing”. Poughkeepsie, NY: IBM Data Systems Division Development Laboratories, TR 00.1173, July 28, 1964. Earliest known use of a hardware instruction coverage monitor: COBOL and FORTRAN source. Weinberg, Gerald M„ and Freedman, D.P. “Handbook of Walkthroughs, Inspections and Technical Reviews”. New York: Dorset House, 1990. Weiser, Mark D. “Program Slicing.” Proceedings of the Fifth International Conference on Software Engineering (439-449) March 1981. Weiser, Mark D. “Program Slicing.” IEEE Transactions on Software Engineering SE-10 (1984), pp. 352-357. Weiser, Mark D., Gannon, John D., and McMullin, Paul R. “Comparison of Structural Test Coverage Metrics.” IEEE Software (March 1985), 80-85. Weiss, Stewart N. and Franki, Phyllis G. “Comparison of All-Uses and All-Edges: Design, Data, and Analysis.” Hunter College, New York, Dept, of Computer Science, Technical Report CS-TR 91-04. Weyuker, Elaine. J. “The Cost of Data Flow Testing — An Empirical Study.” IEEE Transactions on Software Engineering 16 (February 1990). Weyuker, Elaine J. “Data Flow Testing”. In MARC94, pp. 247-249. Key theoretical concepts and definitions for structural data flow testing. White, Lee J., Cohen, E. I., and Chandrasekaran, B. “A Domain Strategy for Computer Program Testing.” Columbus, OH: Computer and Information Science Research Center, Ohio State
WHIT80 WHIT85 WHIT87 WHIT94 WHIT95 WILK77 WING94 WILS82 YERH80 YOSH87 ZEIL83 ZEIL89 ZUSE90 University, Technical Report OSU-CISRC-TR-78-4, August 1978. White, Lee J„ and Cohen, E. I. “A Domain Strategy for Computer Program Testing.” IEEE Transactions on Software Engineering 6 (1980), pp. 247-257. Use of linear predicates and associated inequalities to establish test cases, boundary choices, etc. Generalization to n-dimensional problems. White, Lee J., and Sahay, P. N. “A Computer System for Generating Test Data Using the Domain Strategy.” IEEE SOFTFAIR Conference II, San Francisco, CA, December 2-5, 1985. White, Lee J. “Software Testing and Verification.” In Advances in Computers, vol. 26, pp. 335-391. New York: Academic Press, 1987. Superior tutorial and overview of theory. White, Lee J., and Leung, Hareton K. N. “Integration Testing.” In MARC94, pp. 573-577. White, Lee J. “Consistency and Completeness Checking of Domain Specifications.” 12th International Conference on Testing Computer Software. Washington, DC, June 12-15,1995. Wilkens, E. J. “Finite State Techniques in Software Engineering.” (First) Computer Software and Applications Conference, Chicago, IL, November 1977. Application of finite-state machine models to software design. Wing, Jeannette, M. “Formal Methods.” In MARC94, pp. 504-517, p.12. Wilson, C., and Osterweill, L. J. “A Data Flow Analysis Tool for the C Programming Language.” Sixth Computer Software and Applications Conference, Chicago, IL, November 8-12, 1982. Yeh, R. T, and Zave, P. “Specifying Software Requirements.” IEEE Proceedings 68 (1980), pp. 1077-1085. Examines specifications as a source of program bugs and suggests methodology for specification design. Yoshizawa, Y„ Kubo T, Satoh, T, Totsuka, K„ Haraguchi, M„ and Moriyama, H. “Test and Debugging Environment for Large Scale Operating Systems.” Eleventh International Computer Software and Applications Conference, Tokyo, Japan, October 7-9, 1987. Zeil, S. J. “Testing for Perturbations of Program Statements.” IEEE Transactions on Software Engineering SE-9, 3 (May 1983), pp. 335-346. Zeil, S. J. “Perturbation Techniques for Detecting Domain Errors.” IEEE Transactions on Software Engineering 15, 8 (June 1989), pp. 737-746. Zuse, Horst. “Software Complexity. Measures and Methods”. New York: Walter de Gruyter, 1990. Encyclopedic book on metrics.
ZUSE94 Zuse, Horst. “Complexity Metrics/Analysis.” In MARC94, pp. 131-165. Excellent survey of the theory and practice of software metrics. ZWEB92 Zweben, Stuart H., Heym, Wayne D„ and Kimmich, J. “Systematic Testing of Data Abstractions Based on Software Specifications.” Journal of Software Testing, Verification, and Reliability 1, #4 (January-March, 1992), pp. 39-55. Use of control-flow and data-flow models based on specifications and application of analogous structural test techniques. Experimental results shows relative technique strengths and effectiveness similar to that obtained for structural testing.
Алфавитный указатель А Активизация, 83 Алфавит, 211 Анализ, 42 Анализ требований, 37 Б БНФ, 215 В Валидация, 28 Вариант, 28 Ввод, 27 Веса связей, 187,218, 242 Веса узлов, 187 Вес связи, 46, 155 Вес узла, 45 Вложенные циклы, 99 Внешняя точка. 182 Внутренняя точка, 182 Входная переменная, 179 Входное кодирование, 238 Входное пространство, 180 Входное событие, 238 Входной узел, 48, 115 Входной вектор, 180 Входные символы, 238 Входящая связь, 48 Вырожденная граница, 182 Вырожденный домен, 182 Выходная переменная, 180 Выходное пространство, 180 Выходное событие, 239 Выходной вектор, 180 Выходной узел, 49 Г Гибридный тест, 34 Гиперплоскость, 181 Голова строки, 214 Грамматический разбор, 213 Граница домена, 180 Граничное множество домена, 180 Граничное неравенство. 180 Граничное уравнение, 180 Граф, 44,47 Граф потока данных, 118 Грязный тест, 32 д Дна прохода, 105 Детерминированный цикл, 98 Длина пути, 50 Домен, 180 Дорожная карта процесса, 41 Доступное состояние, 240 3 Завершающий узел, 153 Задача, 153 Законченная граница, 183 Закрытые границы, 181 Закрытый домен, 181 Запоминающий узел, 115 Значение связи, 117 И Изолированные состояния, 240 Или, 214 Имя пути, 49 Имя связи, 46 Имя узла, 45 Имя строки, 212 Инструменты. 39
Интеграция, 30,43 Интерпретация команды, 213 Интерпретация предиката, 85 Интерпретация предикатов, 190 Интерфейс, 29 Искаженность, 28 Использование, 115 Использование в предикате, 115 Использование для вычислений, 114 Исходящая связь, 48 Итог, 27 К Ключевое слово, 213 Кодирование выхода, 239 Код состояния, 238 Количественные измерения, 41 Команда, 212 Командно-управляемое ПО, 212 Командный язык, 212 Комплементарные сегменты пути, 65 Компонент, 29 Конечное состояние, 27 Конечный автомат, 239 Конкатенация, 214 Константы, 115 Контрольная запись транзакции, 153 Контроль конфигурации, 41 Коррслированныепредикаты, 65 Критерии завершенности, 42 Критерии соответствия, 28 Критерии соответствия требованиям, 42 Критерий всех использований, 141 Критерий готовности, 42 Критические тестовые значения, 105 Л Лексическая эквивалентность, 213 Лексический анализ, 214 Линейное неравенство, 183 Линейно зависимый, 183 Линейно независимые точки, 183 Линейно независимый, 183 Линейный домен, 183 Логический предикат, 64 Логический оператор, 114 Логическое И, 64 Логическое ИЛИ, 64 Логическое НЕ, 64 м Максимум, 105 Маркер транзакции, 153 Маркировка, 156 Марковский граф, 155 Марковский узел, 155 Металингвистические символы, 212 Метасимволы, 212 Методы тестирования, 33 Метрики, 41 Множественная обработка, 158 Модели Мили, 245 Модели Мура, 245 Модули. 30 Модуль, 29 н Наблюдаемый, 27 Набор выходных состояний, 241 Набор начальных состояний, 240 Набор строк, 212 Направленная связь, 46 Направленный граф, 47 Начальное состояние, 27,238 Негативный тест, 32 Недетерминированный цикл, 98 Недоступное состояние, 240 Независимые предикаты, 65 Незаконченная граница, 184 Нелинейный домен, 183 Непаправлснпаясвязь, 47 Ненаправленный граф, 48 Необходимые циклы, 129 Необязательное поле, 216 Неопределенность доменов, 192 Непоследовательное закрытие, 184 Непроходимый путь, 49 Нециклический путь, 50 Нулевой набор, 214 Нуль, 212 О Обезглавливание, 215 Область, 180 Обрабатывающий узел, 116 Обход, 105 Обход из начального состояния, 241 Объединение, 215 Объект, 27,51,52,65, 155, 186 Одиночный произвольный символ, 216 Один проход, 105 Окружение, 31 Операнд, 213 Оператор, 213 Операторы ветвления, 52 Оператор «звезда», 215 Определение БНФ, 215 Определение объекта, 114 Опровергаемый, 27 Оракул, 27 Ответственность, 42 Открытые границы, 181 Открытый домен, 181
Отношение, 45,51,52,66, 155, 186, 218 несимметричное, 53 рефлексивное, 54 симметричное, 53 транзитивное, 52 Отношение эквивалентности, 55 Очередь, 156 Очередь многосерверная, 158 односерверная, 158 Очередь по приоритету, 158 Ошибка, 28 Ошибка безопасности, 30 Ошибка интеграции, 30, 35 Ошибка компонента, 30 Ошибка модуля, 29,35 Ошибка потери ресурсов, 30 Ошибка производительности, 30 п Пакет, 158 Параллельные связи, 46 Перегрузка, 114 Переменная управления циклом, 98 Переход в себя, 239 Переходы, 239 Плюс в показателе, 215 Поведенческое тестирование, 12 Подграф, 132 Подпрограммы, 30 Подсистемы, 30 Подстрока, 215 Подтест, 27 Позитивный тест, 32 Показатель степени, 214 Покрытие ввода/вывода, 134 Покрытие связей, 188 Покрытие узлов, 187 Полностью определенный автомат, 241 Порожденный подграф, 133 Порожденный подграф потока данных, 133 Последовательное закрытие, 184 Правило FIFO, 157 Правило LIFO, 157 Предикат ветвления, 153 Предикат выбора, 64 Предикат управлепияциклом, 98 Предикат выбора данных, 117 Проверка связей, 59 Проверка узлов, 59 Проверка соответствия, 28 Проверка соответствия проекта, 42 Программирование, 42 Программы, 30 Проектирование, 38, 42 Проектирование теста, 27 Произвольная последовательность симво- лов, 216 Прослеживаемость требований, 41 Протестирован, 29 Противоречивость доменов, 192 Проходимый путь, 49 Пустой выход, 240 Пустой символ, 212 Путь, 49 Путь вход — выход, 49 Р Рабочее состояние, 241 Разделитель, 213 С Само тестирован не, 38 Сброс, 240 Свободен от ошибок, 29 Свойства, 52 Связи, 51, 52, 242 Связь, 45 Сегмент иу in, 49 Сегмент границы, 184 Семантический анализ, 213 Сильно связанные состояния, 240 Символ пробела, 212 Симптом, 28 Синтаксис, 212 Синтаксический анализ, 213 Системная ошибка, 30 Системное тестирование, 35 Системы программного обеспечения, 30 Слепота, 29 Случайная корректность, 29 Случайное обслуживание, 158 Смежные домены, 182 Соединительный узел, 67 Создание прототипа, 37 Составной предикат, 65 Состояние, 27, 237 Состояние транзакции, 153 Спецификация, 28 Сравнение итогов, 28 Стартовый узел, 153 Стратегические тонкости, 42 Стратегия тестирования, 33 Строка, 212 Строковое поле, 213 Структурный тест, 33 Сценарий теста, 28 Счетчик состояний, 238 т Текущее состояние, 238 Тест, 27 Тестирование, 27,43
Тестирование интеграции, 29 Тестирование компонента, 30 Тестирование модуля, 29 Тестирование системы, 30 Тестовый комплект, 27 Типичное число проходов, 105 Тин транзакции, 153 Тире, 212 Транзакция, 153 Требования, 27,41 У Ужасные циклы, 103 Узел, 45,218,242 Узел ветвления, 48, 153 Узел входа в цикл, 98 Узел выбора, 66 Узел выхода из цикла, 98 Узел поглощения, 154 Узел порождения, 154 Узел расщепления, 154 Узел слияния, 154 Узел соединения, 154 Узел с предикатом, 66 Узел управления циклом, 98 Узел выбора данных, 117 Узел вывода, 115 Узловая точка, 181 Укорачивание, 215 Управление процессом, 41 Управляющаявходящаясвязь, 117, 153 Ф Формальное инспектирование, 38 Формальный анализ, 37 Форма Бэкуса Наура, 215 Функциональное тестирование, 12 Функциональные клавиши, 243 X Характеристика, 28 Хвост строки, 214 ц Цикл, 50,60,98 Цикл со смешанной проверкой, 99 Цикл с постусловием, 99 Цикл с предусловием, 98 ч Частичное покрытие узлов, 135 Число повторений цикла, 98 Число входных символов, 238 Число состояний, 239 Чистый тест. 32 э Эпсилон-окрестность, 182
Борис Бейзер Тестирование черного ящика. Технологии функционального тестирования программного обеспечения и систем Перевел с английского А. Раздобарин Главный редактор Заведующий редакцией Руководитель проекта Научный редактор Литературный редактор Иллюстрации Художник Корректоры Верстка Е Строганова И. Корнеев А Крузенштерн С. Орлов И. Шапошников М. Шендерова Н Биржаков Д. Стукалин. А. Моносов К. Кузьминский Лицензия ИД №05784 от 07.09.01. Подписано к печати 19.06.04. Формат 70x100/16. Усл. п. л. 25,8. Тираж 3000. Заказ 770 ООО «Питер Принт», 196105, Санкт-Петербург, уп. Б-'iai одатнэя, д. 67ь. Налоговая льгота — общероссийский классификатор продукции ОК 005-93, том 2; 95 3005 — литература учебн Отпечатано с готовых диапозитивов в ОАО «Техническая книпк 190005, Санкт-Петербург, Измайловский пр., 29
ИЗДАТЕЛЬСКИЙ дом WWW.PITER.COM СПЕЦИАЛИСТАМ КНИЖНОГО БИЗНЕСА! ПРЕДСТАВИТЕЛЬСТВА ИЗДАТЕЛЬСКОГО ДОМА «ПИТЕР» предлагают эксклюзивный ассортимент компьютерной, медицинской, психологической, экономической и популярной литературы РОССИЯ Москва м. «Калужская», ул. Бутлерова, д. 176, офис 207, 240; тел./факс (095) 777-54-67; e-mail: sales@piter.msk.ru Санкт-Петербург м. «Выборгская», Е Самисониевский пр., д. 29а; тел. (812) 103-73-73, факс (812) 103-73-83; e-mai' sales@piter.com Воронеж ул. 25 января, д. 4; тел (0732) 27-18-85, e-mail: piter-vrn@vmail.ru; piterv@comch.ru Екатеринбург ул. 8 Марта, д. 2676; тел./факс (343) 225-39-94, 225-40-20; e-mail: piter-ural@r66.ru Нижний Новгород ул. Премудрова, д. 31а; тел. (8312) 58-50-15, 58-50-25; e-mail: piter@infonet.nnov.ru Новосибирск ул. Немировича-Данченко, д. 104, офис 502; тел/факс (3832) 54-13-09,47-92-93, 11-27-18, 11-93-18; e-mail: piter-sib@risp.ru Ростов-на-Дону ул. Калитвинская, д. 17в; тел. (8632) 95-36-31, (8632) 95-36-32; e-mail: jupiter@rost.ru Самара ул. Новосадовая, д. 4; тел. (8462)37-06-07; e-mail: piter-volga@sama.ru УКРАИНА Харьков ул. Суздальские ряды, д. 12, офис 10-11, т. (057) 712-27-05, 712-40-88; e-mail: piter@tender.kharkov.ua Киев пр. Красных Казаков, д. 6, корп. 1; тел./факс (044) 490-35-68,490-35-69; e-mail: office@piter-press.kiev.ua БЕЛАРУСЬ Минск ул. Бобруйская д., 21, офис 3; тел./факс (37517) 226-19-53; e-mail: piter@mail.by МОЛДОВА Кишинев «Ауратип-Питер»; ул. Митрополит Варлаам, 65, офис 345; тел. (3732) 22-69-52, факс (3732) 27-24-82; e-mail: lili@auratip.mldnet.com Ищем зарубежных партнеров или посредников, имеющих выход на зарубежный рынок. Телефон для связи: (812) 103-73-73. E-mail: grigorjan@piter.com Издательский дом «Питер» приглашает к сотрудничеству авторов. Обращайтесь по телефонам: Санкт-Петербург - (п12) 327-13-11, Москва - (095) 777-54-67. Заказ книг для вузов и библиотек: (812) 103-73-73. Специальное предложение - e-mail: kozin@piter.com
www.cnews.ru интернет-издание о высоких технологиях Широта охвата: В поле зрения новостного отдела CNews находятся рынки телекоммуникаций. компьютерного оборудования, программного обеспечения, электронного бизнеса, защиты информации. Массовость: Ежедневно более 30 тыс. читателей посещают наш сайт. Ежемесячная аудитория издания - более чем 300 тыс. человек по всей России и за рубежом. E-mail: news@cnews.ru Тел.: +7 (095) 363 11-57 □CNews Analytics исследования и обзоры рынков ИТ www.cnews.ru/reviews Исследования: Экспертами CNA подготовлены десятки обзоров по различным сегментам российского рынка ИТ. Тренинги: За последний год в Школе CNews учебные курсы прошли более 900 руководителей и специалистов. E-mail: review@rbc.ru Тел.: +7 (095) 363-11-11
Борис Бейзер — всемирно известный консультант по проблемам разработки ПО «за плечами» которого уже сорок лет работы в IT-индустрии. Первопроходец в области тестирования, автор множества книг, посвященных данной тематике, две из которых — Software Testing Techniques и Software System Testing and Quality Assurance — долгое время считались общепризнанными стандартами Представляем вашему вниманию практическое, доступное руководство по современным методам тестирования черного ящика, написанное ведущим специалистом по данной проблематике. Эту книгу ждали давно. Именно такую — практичную и понятную, освещающую основные аспекты тестирования черного ящика. Больше других ее ждали разработчики программного обеспечения, создатели больших программных систем. И вот она, наконец, вышла из-под пера Бориса Бейзера — одной из самых значительных фигур в области тестирования. Это руководство, вне всяких сомнений, станет превосходным подспорьем для независимых тестировщиков и программистов и ценным практическим пособием для студентов. Пожалуй, на сегодняшний день это единственная книга, в которой доступным языком описываются принципы поведенческого тестирования в целом и наиболее существенные современные методы тестирования черного ящика, среди которых функциональное тестирование, тестирование на соответствие заявленной спецификации. В таком руководстве не может не быть полноценных примеров, поясняющих шаг за шагом весь процесс тестирования, и они там есть. Основные достоинства книги, которые убедят вас в том, что вы сделали правильный выбор, взяв ее с полки: ♦ исчерпывающее описание всех наиболее важных методов тестирования, включая те, которые применяются при разработке объектно-ориентированных программ; ♦ соответствие современным требованиям — с учетом последних достижений в области тестирования, позволяющих тестировщику работать, имея под рукой только калькулятор или листок бумаги; ♦ контрольные задания — вы сможете самостоятельно оценить глубину понимания материала. Посетите наш web-магазин: www.piter.comx ПИТЕР WWW PITER COM