Вы находитесь на странице: 1из 321

Тестирование

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

Борис Бейзер
Boris Beizer

Wiley
John Wiley & Sons, Inc.
New York ■ Chichester ■ Brisbane ■ Toronto ■ Singapore
Борис Бейзер

Е^ППТЕР*
Москва • Санкт-Петербург ■Нижний Новгород ■Воронеж
Новосибирск • Ростов-на-Дону • Екатеринбург • Самара
Киев ■Харьков ■Минск
2004
ББК 32.973-018-07
УДК 681.3.06
Б 41

Бейзер Б.
Б 41 Тестирование черного ящика. Технологии функционального тестирования
программного обеспечения и систем. — СПб.: Питер, 2004. — 318 с.: ил.
ISBN 5-94723-698-2

Книга доктора Бейзсра «Тестирование черного ящика» давно была признана классическим
трудом в области поведенческого тестирования разнообразных систем. В ней глубоко
рассматриваются основные вопросы тестирования программного обеспечения, позволяющие
отыскать максимум ошибок при минимуме временных затрат. Чрезвычайно подробно излагаются
основные методики тестирования, покрывающие все спектры испек гов разработки программных
систем. Методичность и широта изложения делают эту книгу незаменимым помощником при
проверке правильности функционирования программных решений.
Книга предназначена для тестировщиков программного обеспечения и программистов,
стремящихся повысить качество своей работы.

ББК 32.973-018-07
УДК 681.3.06

Права на издание получены по соглашению с издательством Wiley.


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

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

© by John Wiley & Sons, Inc


ISBN 0-471-12094-4 (англ.) © Перевод на русский язык, ЗАО Издательский дом «Питер», 2004
ISBN 5-94723-698-2 © Издание на русском языке, оформление ЗАО Издательский дом «Питер», 2004
Содержание

Введение............................................................................................ 12

Пропущенные модели......................................................................... 14
1. Общие положения.......................................................................................... 14
2. Маерс. «Искусство тестирования программ».................................................14
3. Логические модели........................................................................................ 16
4. Языковые модели.......................................................................................... 16

README.DOC........................................................................................18
Зачем нужен Readm e.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
6 Содержание

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
Содержание 7

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 • Тестирование потоков данных.......................................... 113


5.1. О б з о р .......................................................................................................и з
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
8 Содержание

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 • Тестирование потоков транзакций.................................... 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.6. Фокус и иерархические модели................................................... 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
Содержание 9

Глава 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.4.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
10 Содержание

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
Содержание 11

10.5.3. Зачем и почему я не верю в независимое тестирование............280


10.5.4. Будущее тестирования ............................................................. 281
10.6. Вопросы для самопроверки................................................................... 282

Приложение А ....................................................................................283

Список литературы........................................................................... 299

Алфавитный указатель..................................................................... 314


Введение

Для кого написана эта книга? Для разработчиков и тестировщиков программно­


го обеспечения. Говоря «тестировщик», я имею в виду людей, которые регулярно
или в настоящее время тестируют программы, написанные другими людьми. Под
«разработчиками» я подразумеваю людей, разрабатывающих программное обес­
печение, но, сейчас занимающихся тестированием своих программ. Тестирование,
выполняемое и теми и другими, слабо зависит от внешнего вида программы, оно
подразумевает, что вы ставите себя на место пользователя и проверяете, что про­
грамма ведет себя так, как должна, вне зависимости от способа ее создания. Это
и означает тестирование методом черного ящика.
Большинству начинающих тестировщиков, особенно если они нигде этому
не учились, приходится самим исследовать тестирование методом черного ящи­
ка (иначе его называют поведенческим тестированием или функциональным тес­
тированием). Без соответствующей подготовки они изучают по книгам эвристи­
ческие версии методов, для которых могут существовать специально написанные
коммерческие инструментальные средства. Для таких пользователей в данной
книге содержатся основные сведения о надежных и доступных методах поведен­
ческого тестирования.
На освещение этих вопросов меня подталкивали производители инструментов
для тестирования, поскольку они создают сложные продукты, основанные отчас­
ти на технологиях, описанных в этой книге, но пользователи не владеют методами,
реализованными в их инструментах. Возникает замкнутый круг. Тестировщики
с большой неохотой вкладывают деньги в обучение новым методам. Особенно те
из них, кто полагается на автоматику, хотя для этого уже существуют специаль­
ные коммерческие инструменты. Производители не могут инвестировать средс­
тва в разработку инструментов, включающих такие методы, пока не появятся тес­
тировщики, владеющие этими методами. Эта книга призвана помочь разрушить
замкнутый круг. Прочитайте ее, затем отправляйтесь к производителю, чьими ин­
струментальными средствами вы пользуетесь, и требуйте включить в них методы
Введение 13

из соответствующей главы. А если я отправлю производителям данные о прода­


жах этой книги, это будет для них явным признаком того, что риск обоснован, так
как на самом деле существует рынок спроса на их инструменты и большое число
опытных тестировщиков, понимающих особенности методов и принципов, на ко­
торых они основаны.
Я должен сказать, чего в этой книге нет. Она не вмещает в себя огромный объем
литературы по тестированию, так, например, она не заменяет мою книгу «Методы
тестирования программного обеспечения», 2-е издание ([SST2 — BEIZ90]).
SST2 — это всеобъемлющий (550 страниц) обзор литературы по тестированию.
Эта книга предназначена для максимально широкой аудитории — от разработчи­
ков, до тестировщиков, исследователей, студентов и аспирантов. Настоящая кни­
га слишком мала, чтобы выполнить такую работу. Здесь не рассматриваются воп­
росы дизайна программ, в отличие от SST2, где они присутствуют почти в каждой
главе. SST2 охватывает как структурное тестирование, так и поведенческое тести­
рование. Здесь же обсуждается лишь тестирование поведения. Эта книга также не
может заменить работы «Тестирование программного обеспечения и обеспечение
качества» [BEIZ84] или моей следующей книги «Интеграция и тестирование сис­
тем», над которой сейчас идет работа [BEIZ96]. Там речь идет о системном тести­
ровании и тестировании интеграции систем, а обсуждаемые методы используются
для создания тестов интеграции и тестов систем. В книге «Интеграция и тестиро­
вание систем» я буду считать, что вы прочитали эту книгу и знакомы с соответс­
твующими методами.
В данной книге вы не встретите теоретических аспектов тестирования. Я не
буду доказывать теорем и упомяну лишь о немногих. Эта книга для практиков.
Тем не менее, вы можете быть уверены, что все, что имеет под собой прочную те­
оретическую базу, основано на этих теоремах. Как следствие моей попытки со­
ответствовать теоретическим нюансам, временами текст, а особенно определе­
ния, могут показаться излишне формальными, очень похожими друг от друга и
на первый взгляд не имеющими прямого отношения к вопросу. Если такое слу­
чится, то будьте уверены, что в дополнительной литературе вы найдете ответы на
свои вопросы, поскольку эта книга полностью согласуется с литературой по дан­
ной тематике.
Еще несколько вещей, которые я не собираюсь здесь делать. Я не собира­
юсь тратить ваше время, рассуждая, насколько важны тестирование и качество.
Если вы еще этого нс знаете, то вам полезнее будет подумать над этим вопро­
сом. Также я не стану распространяться об обеспечении качества, менеджмен­
те, организации, политике, финансах, культуре, становлении программистского
эго, о том, кто должен тестировать программное обеспечение, надо ли тестиро­
вать программное обеспечение, нужны ли нам законы, обеспечивающие качест­
во программного обеспечения, открытых системах, свободно распространяемых
программных средствах, проблеме наркотиков или моральном облике современ­
ной молодежи. Все это очень интересно. Я оставляю эти темы вам для обсужде­
ния и исследования. Если же вы хотите освоить методы поведенческого тести­
рования с минимумом предварительных условий и хлопот, тогда, я надеюсь, эта
книга вас не разочарует.
Пропущенные
модели

1. Общие положения
Этот раздел для читателей, знакомых с литературой по тестированию, в особеннос­
ти читателей книги Глена Маерса «Искусство тестирования программ» [MYER79];
читателей, которые могут быть озадачены, если я не расскажу о нескольких мето­
дах поведенческого тестирования. В первую очередь о логических моделях.
Сначала я поставил себе цель уложиться в 175-страничную книгу. Этот объем
вполне подходит для прочтения за один семестр. Одновременно планировалось,
что эта книга заменит устаревший шедевр Маерса. Маерс уложился в 191 страницу.
Когда я начал писать, для меня стало очевидно, что примеры занимают больше мес­
та, чем я предполагал. Я добавил некоторые новые технические требования, и это оз­
начало, что мне придется включить больше материала, чтобы книга была самодоста­
точной. Цель «175 страниц» была недостижима, и, тем не менее, мне приходилось
постоянно себя ограничивать, сокращая материат.
Мои технические семинары служили обратной связью для определения тем, кото­
рые наиболее интересны людям. Я проводил их свыше 200 раз на протяжении 10 лет
для тысяч тестировщиков. Участники семинара заполняли опросный лист, в котором
спрашивалось, какие методы, по их мнению, могут быть полезны для них сразу же, а
какие могут пригодиться в будущем (скажем через 3-5 лет). Я поддерживаю связь с
бывшими студентами и оргапизациями-заказчиками, чтобы определить, какие методы
они используют при тестировании. Эта обратная связь лежит в основе данной книги.

2. Маерс. «Искусство тестирования программ»


Книга «Искусство тестирования программ» освещает вопросы тестирования так,
как их понимали в 1979 году. С тех пор прошло более двух десятилетий, техноло-
2. Маерс. «Искусство тестирования программ» 15

гии тестирования развивались, и читатели не будут удивлены, обнаружив, что тех­


ника тестирования тоже изменилась. С одной стороны, сегодня мы знаем о тести­
ровании гораздо больше. С другой стороны, создание подобного обзора потребует
сейчас не одной, а целых семи книг: «Инспектирование», «Методы тестирования»,
«Тестирование интеграции», «Системное тестирование», «Теория тестирования»,
«Методы отладки», «Организация тестирования» и «Менеджмент». Моя задача
существенно уже — введение в технику тестирования. Вот современное описание
пяти методов, обсуждаемых Маерсом.
1. Тестирование путем покрытия логики. То, что Маерс называл «тестирова­
нием путем покрытия логики», в настоящее время называется тестировани­
ем потока управления (глава 3). Поскольку в данной книге рассматривают­
ся не структурные методы (белого ящика), а лишь поведенческие методы
(черного ящика), я остановлюсь лишь на поведенческом тестировании по­
тока управления.
2. Разбиение по эквивалентности. Все методы тестирования, описанные в
этой книге, основаны на идее разбиения набора всех возможных входных
данных на классы эквивалентности (глава 3). Это означает, что все они от­
носятся к методам тестирования путем разбиения. Маерс настоятельно со­
ветовал читателям исследовать код и спецификации, а затем на их осно­
ве осуществлять разбиение входных данных на эквивалентные классы для
тестирования программы. Он также предложил для этого несколько слож­
ных эвристических правил. Это выливается в создание специальных мето­
дов для каждой конкретной программы. Принцип, конечно, правильный и
абсолютно корректный, но на практике тестировщики испытывают трудно­
сти при определении этих смутных (хоть и плодотворных) классов эквива­
лентности. Я расскажу вам об уже готовых методах разбиения на классы эк­
вивалентности (или методах тестирования), что облегчает их практическое
использование.
3. Анализ граничных значений. Рассуждения Маерса об анализе граничных
значений являются частью более общей и более мощной методологии тес­
тирования доменов (глава 7). Некоторые аспекты анализа граничных зна­
чений в применении к циклам будут обсуждаться в главе 4.
4. Причинно-следственные диаграммы [ELME73, MYER79]. Более подроб­
ное обсуждение вопроса, почему причинно-следственные диаграммы и свя­
занные с ними методы не включены в данную книгу, приводится в разделе 3
«Логические модели». Такие методы трудны в практическом использова­
нии потенциальными тестировщиками, не обладающими необходимыми
знаниями, такими как булева алгебра или теория переключательных схем.
Остранд [OSTR88] замечательно отозвался об этой технике: «Переводя
данные спецификации в причинно-следственные диаграммы, тестировщи­
ки замещают одно сложное представление другим».
5. Предположение об ошибках. При выборе метода тестирования мы делаем
ставку на определенный тип ошибок, который ожидаем обнаружить, так
16 Пропущенные модели

как предположение о типе ошибок присутствует в любом методе. Поэтому


предположение об ошибках —это не какой то метод тестирования, но атри­
бут любого из методов. Предположение об ошибках, основанное на статис­
тике ошибок программистов, — вполне здравая идея (посмотрите, однако,
«Парадокс пестицида» в главе 1). Сегодня мы имеем подобные статистики и,
опираясь на них, выбираем определенный метод тестирования. Существует
также и формальная теория тестирования, основанного на ошибках, но она
не вошла в эту книгу [HOWD89, MORE90].

3. Логические модели
Логические модели включают в себя причинно-следственные диаграммы [ELME73,
MYER79], модели таблиц решений [BEIZ90, GOOD75] и множество других ва­
риантов, использующихся в качестве частей различных методологий дизайна
[BEND85, WEYU94B]. Это замечательные методы, однако для их разбора пот­
ребуется слишком много места. К примеру, логические модели занимают в книге
«Методы тестирования программного обеспечения» 42 страницы. В данной книге
из-за более современных предпосылок и примеров черновик состоял из 75 стра­
ниц. Это еще две дополнительные большие (даже слишком большие) главы, что
сделает курс слишком большим для одного семестра.
Мне трудно объяснить логические модели без привлечения булевой алгебры,
а ее нет смысла учить, если вы не владеете диаграммами Карно—Вейча [BEIZ90],
поскольку булева алгебра почти не используется без этого важного инструмента.
Я обратил внимание, что слушатели разделяются на две категории. Те, кто знаком
с булевой алгеброй и картами Карно, способны овладеть этими методами само­
стоятельно, например, с помощью STT2. Те же, у кого нет таких знаний, не могут
изучить их за четыре часа, которые я посвящаю этой теме. В итоге тестирование
на основе логики всегда находится на последних местах в списке предпочтений
моих студентов и спонсоров. И я частенько вообще выбрасываю эту тему из моих
семинаров.
Было бы неплохо, чтобы курс по тестированию был не единственным. Вспо­
могательный курс, для начальных или старших курсов, когда студенты уже владе­
ют необходимыми знаниями, мог бы включать в себя логические модели и другие
модели, здесь не представленные.

4. Языковые модели
Существует большое число моделей на основе специальных языков для разра­
ботки тестов и связанных с ними инструментальных средств. Хорошим приме­
ром может служить метод разбиения по категориям Остранда [LAYC92, OSTR88]
и «Т» Постона [POST94], Другие методы того же типа изложены в [BALC89,
BELF76, DAVI88, КЕММ85, RICH89]. Все эти методы основаны на языке опре­
деления теста. Языки отличаются степенью формальности и выразительной си­
лой, простираясь от самых элементарных до строгих полнофункциональных язы­
4. Языковые модели 17

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


программ. Языковый процессор проверяет это определение на неоднозначности
и противоречия. Другой процессор автоматически генерирует тестовые варианты
(положительные и отрицательные), соответствующие данному определению при
помощи большого числа формальных и эвристических методов тестирования.
Что же плохого в таком способе? Ничего. Я люблю его. Я верю, что рано или
поздно тесты будут преимущественно создаваться такими вот инструментами.
Однако подобные средства сложны, и их нельзя понять по-настоящему без пони­
мания методов тестирования, на которых строятся генераторы тестов. Прочтя эту
книгу, вы узнаете об этих методах.
Другая проблема является фундаментальной для любого языка программи­
рования. Один из наиболее важных выводов, которые я сделал, наблюдая почти
четыре десятилетия за развитием программного обеспечения, заключается в том,
что нельзя ставить все на какой-то язык программирования, пока он популярен.
Да и после потери популярности не стоит зацикливаться на нем. Люди предре­
кали кончину языка 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. Вы —в большинстве своем тестировщики-практики, и я не буду осуждать вас,
План книги 19

если вы пропустите главу, которая покажется вам чересчур абстрактной или не


имеющей отношения к вашей конкретной задаче. Прошу за это прощения. Глава 2
очень важна. Если вы не разберетесь в ней, то последующие главы могут быть не­
понятны. В лучшем случае вы не сможете извлечь из них столько пользы, как если
бы вы прочитали эту главу.
Глава 2 подобна подпрограмме с нужной информацией. Вместо того чтобы
снова и снова повторять основные принципы в различных контекстах для каждой
главы, я опишу идеи тестирования один раз в абстрактной форме и буду ссылать­
ся на них в дальнейшем. Если вы разберетесь в абстрактных понятиях главы 2, то
в последующих главах объяснение методов будет занимать всего несколько стра­
ниц. Это сделает книгу короче и дешевле, а КПД усвоения выше.
В главах с 3 по 9 описываются конкретные методы. В каждой главе —один ме­
тод и его производные. Я постарался сделать эти главы как можно более независи­
мыми друг от друга. Переварив главу 2, вы сможете читать остальные главы прак­
тически в любом порядке.

1-ВВЕДЕНИЕ
/ ~ Т — |----Г“* \

/ f * 1ч

Данная диаграмма показывает, какой материал должен быть предварительно


освоен перед прочтением той или иной главы. Сплошные линии означают, что
вы должны разобраться в главе, находящейся в начале стрелки, для того чтобы
понять главу, па которую стрелка указывает. Прерывистые линии означают, что
предварительная глава содержит определения, которые будут использоваться в
последующей главе, но любом случае вы сможете понять материал без вниматель­
ного изучения предварительной главы. Прочтение главы 1 — желательно, но не­
обязательно для понимания следующих глав. Последняя глава включает в себя
20 Readme.doc

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


нежесткое.
В последней главе рассказывается об инструментальных средствах и авто­
матизации. И хотя методы, описываемые в этой книге, могут использоваться и
безо всякой автоматизации, такое их использование будет крайне неэффективно.
Я надеюсь, что вы простите мне, что я не вдаюсь в подробности при обсуждении
инструментальных средств. Я не собирался делать здесь полный обзор послед­
них коммерческих инструментов. Такую информацию можно найти в [DAIC93],
[GRAH93], [SQET94] и других подобных периодических изданиях. Ситуация ме­
няется слишком быстро, для того чтобы имело смысл печатать подобную инфор­
мацию в книге.

Структура главы
Главы с 3 по 9, составляющие ядро данной книги, имеют сходную структуру, хотя
порядок может меняться от главы к главе.
Обзор. Содержание главы в общих словах без использования терминов, вводи­
мых в данной главе.
Словарь внешних терминов. Технические термины, определение которых от­
сутствует в данной книге, но которые вы должны знать. Англоговорящего читате­
ля может удивить, что сюда включено так много основных компьютерных терми­
нов. Около половины содержимого словаря внешних терминов хорошо знакомо
не только профессионалу в области программного обеспечения, но и студенту.
Включая сюда основные термины, я преследовал цель помочь моим многочислен­
ным читателям, для которых английский язык не является родным. Я также на­
деюсь, что эти термины ощутимо облегчат перевод книги. Некоторые из внешних
терминов не принципиальны для понимания книги, поскольку используются
лишь в одной из нескольких иллюстраций идеи или в несущественном коммента­
рии. Не слишком расстраивайтесь, если вы не понимаете термины, используемые
в иллюстрациях, поскольку они играют вспомогательную роль в освоении мето­
дов тестирования. Все такие термины есть в алфавитном указателе, и вы можете
посмотреть их применение в контексте изложения, чтобы понять, действительно
ли они вам нужны для понимания темы.
Словарь внутренних терминов. Термины, определяемые в предыдущей главе.
Словарь новых определений. Определения, используемые в главе. Новые опре­
деления выделяются курсивом. Определение будет выделено курсивом еще раз,
если оно дополняется или уточняется. Определения приводятся в логической по­
следовательности, где каждое следующее определение зависит от предыдущего;
их надо читать в предложенном порядке. Внимательно читайте новые определе­
ния и не двигайтесь дальше, пока их не поняли.
Конфликт словарей. Иногда вы будете находить один и тот же термин во внеш­
нем и внутреннем словарях, а также в словаре новых определений. Когда термин
появляется одновременно во внешнем и внутреннем словарях, это значит, что
если вы знали его и раньше, то у вас не будет проблем с пониманием главы, одна-
Структура главы 21

ко в данном контексте определение будет более строгим, чем то, которое вы зна­
ли. Аналогично, если термин возникает во внутреннем словаре и в словаре новых
определений, то в данной главе он либо уточняется, либо дополняется (переопре­
деляется).
Термины могут выделяться в тексте курсивом (это значит, что вы, скорее всего,
с ними не знакомы), при этом их определение может отсутствовать, и они не бу­
дут включены в словарь новых определений. Это означает, что этот термин ссы­
лается на что-то, что будет определено позже. Я старался избегать таких ссылок
и использовал их, только если чувствовал, что это принесет пользу. Вы, возмож­
но, захотите заглянуть в соответствующую главу и просмотреть определение, но в
любом случае можете не беспокоиться: на изучение данной главы никак не влияет
понимание подобных ссылок.
Модель. Модель, на которой основан метод. Она включает то, что мы принима­
ем во внимание в поведении программы, что игнорируем и как мы представляем
себе это поведение.
Предположение об ошибках. Любой метод тестирования основан на предполо­
жении относительно программного продукта, дизайна, пользователя, типа оши­
бок и возможных проявлений этих ошибок. Этот раздел поможет вам определить
эффективность метода в вашем случае.
Тип приложений. Обсуждение, для каких приложений данный метод, скорее
всего, будет эффективен.
Метод. Метод, что он собой представляет, как он работает и почему он работает.
Примеры. Примеры и решения технических задач — от необходимых требо­
ваний до готовых тестов. Там, где это было возможно, я использовал в качестве
примеров декларацию о доходах внутренней налоговой службы США. Я выбрал
бланки декларации на подоходный налог, поскольку они едины для всех, содер­
жат большое количество нетривиальной логики; они подходят для иллюстраций
большинства методов черного ящика; несмотря на то, что мы затрачиваем огром­
ные усилия, чтобы заполнить бланк декларации и разобраться в этих непостижи­
мых формах, они, тем не менее, представляют собой вполне законченные специ­
фикации и свободны от ошибок; и, наконец, их должен знать каждый.
Предостережения и ограничения. Что данный метод может, чего не может
и ошибки какого типа он пропустит.
Автоматизация и инструментальные средства. Комментарии по поводу ав­
томатической генерации совокупности тестовых данных и инструментальных
средств, построенных на этом методе.
Резюме. Краткое содержание главы с использованием новой терминологии.
При сравнении обзора и резюме становиться понятно, какие новые концепции
были рассмотрены в этой главе.
Тест и упражнения. Упражнения и вопросы по итогам главы. Не прилагая уси­
лий, вы не станете хорошо тестировать. Также вам надо знать терминологию, вве­
денную в этой главе, если она встречается в последующих главах. Станьте сами
себе ОТК. Проверьте себя. Бланки налоговой декларации являются подходящими
объектами для тестирования. Проверьте сделанное, протестировав готовый пакет
налоговых документов. Можете считать, что все правила налоговой службы в нем
22 Readme.doc

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

Бланки налоговой декларации и ссылки на них


Там, где это было возможно, я иллюстрировал методы на примере формы 1040 де­
кларации о доходах внутренней налоговой службы США и дополнений к ней за
1994 год. Копии форм, использующихся в этой книге, содержатся в приложении А.
Эти формы определяют структуры, которые мы и будем тестировать. Я рассчиты­
ваю, что каждый раз, разбирая пример, вы будете сверяться с соответствующей
копией формы.
Я ссылаюсь на различные строки в бланке декларации как «1040 строка 23»
Если отдельно не оговаривается, отсутствие названия формы (например, бланк С)
означает, что ссылка относится к форме 1040. Также для создания полезных при­
меров мы можем добавлять отсутствующие в настоящей форме «строки» в нашу
модель. Так, например, вместо одной строки 34 могут возникнуть строки 34.1,34.2
и т. д.

Что должен знать читатель


Эта книга для людей, обладающих определенными знаниями и опытом. Одного
из нижеследующего будет вполне достаточно: один год (или больше) обучения
по университетской программе в области компьютерных наук или программной
инженерии, два года среднего специального образования в области компьютер­
ных наук или разработки программного обеспечения, интенсивный годовой курс
обучения в сертифицированном коммерческом центре обработки данных или,
что равнозначно, полный курс обучения по направлению «Программное обеспе­
чение» в системе военного образования США, три или больше лет работы про­
граммистом. Занимаетесь ли вы программированием на данный момент —неваж­
но. Важно, чтобы вы знали основные принципы программирования и обладали
практическим навыком. Читателям с опытом прикладного тестирования, но без
опыта программирования будет сложнее. Им придется потрудиться, чтобы понять
и научиться применять главу 2. В словаре внешних терминов для каждой главы
Ссылки 23

приводится лексика, которую вам надо знать для освоения метода. Большинство
людей склонно недооценивать собственные знания. Если вы понимаете термино­
логию главы, этого достаточно для ее изучения.

Не только программное обеспечение


Исходя из вышесказанного, может показаться, что эта книга адресована только раз­
работчикам программного обеспечения и тестировщикам. Это не так. Требования
к читателю достаточно скромны и являются общими при обучении науке, бизне­
су, инженерному делу или бухгалтерии. «Тестирование методом черного ящика»
означает, что нас не интересует, что выступает в роли программно-подобного про­
цесса. Кроме, разумеется, программ, это могут быть химические реакции, физика
электромеханических систем, таинственный ход мыслей юриста, когда он пишет
налоговые законы. Все эти системы надо тестировать. Все методы, представлен­
ные в данной книге, можно применить для тестирования процессов, далеких от
программирования. Если вы биохимик и хотите оптимизировать тестирование ре­
акций, которые используете в анализе крови, эта книга будет вам полезна, пос­
кольку маловероятно, что существует книга о тестировании химических реакций
в крови. Или представьте, что наши законодатели и Конгресс захотят применить
формальный анализ и методы тестирования к абсурдным налоговым законам
(особенно касающимся укрывания налогов), которые они разрабатывают. Тогда
они смогут использовать эту книгу, хотя вряд ли это произойдет.

Использование алфавитного указателя


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

Ссылки
Исследователи вряд ли найдут в ссылках что-нибудь интересное для себя. Ссылки
здесь приводятся для того, чтобы читатель мог узнать больше о теме, иногда озна­
комиться с противоположной точкой зрения или удачными примерами приложе­
ний, которые он мог бы использовать как средство борьбы за внедрение данного
метода в свою организацию. Я ограничил библиографию работ, которые, хотя и
содержат дополнительную информацию, но не являются существенными. Также
я не стал включать в список ссылок множество прекрасных работ, особенно теоре­
тических исследований, не относящихся к теме данной книги.
Ссылки обозначаются согласно требованиям ACM (ассоциация вычислитель­
ной техники). Первые четыре символа из имени автора, затем год публикации, и в
24 Readme.doc

конце заглавная буква, начиная с «А», если это не единственная работа автора за
тот год. Так, например, [BEIZ90] —книга Бейзера, опубликованная в 1990 году, а
[BEIZ91C] — третья его книга в 1991 году. Часто приводится резюме или корот­
кий обзор, если тема не понятна из названия.

Контроль качества
Контроль качества —это ваша задача. Я ожидаю ваших комментариев, а также ва­
ших замечаний об ошибках и недочетах, чтобы исправить их в следующих изда­
ниях. Технологии позволяют сделать это очень просто. Пришлите мне факс или
e-mail по адресам, приведенным ниже. Пожалуйста, сообщите следующую инфор­
мацию о себе:
Ваше имя, место работы (компания, университет, государственное учреждение)
Ваша должность
Почтовый адрес
Номер телефона, факса, e-mail
Название книги, издание
Номер страницы и комментарии или исправления
Если вы используете факс, вы можете сделать копию страницы и написать ком­
ментарий прямо на ней.
В публикациях используются номера, эквивалентные номеру версии и релиза.
«Номер версии» —это то же самое, что и «номер издания», это всегда указывается
в заголовке. Например, «Методы тестирования программ», издание 2-е.
Пожалуйста, посылайте ваши замечания:
Борису Бейзеру
Факс: 215-886-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 (оперативная память), случайный, диапазон, надежность, ресурсы,
1.2. Основные термины 27

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


но используемые данные, имитатор, программное обеспечение, логика програм­
мы, исходный код, область, оператор, статистический, память, управление памя­
тью, подпрограмма, подсистема, инструмент тестирования, таблица, пропускная
способность, истинностное значение, пользователь, значение, переменная.
Объект. Общий термин, включающий в себя данные и программное обеспечение.
Состояние. Набор всех значений всех объектов в данном множестве объектов
в произвольный момент времени. Смысл термина «состояние» зависит от того,
определяет ли он набор объектов и/или их состояний: например, состояние эле­
мента, состояние системы, состояние объекта, начальное состояние.
Начальное состояние. Состояние объекта перед началом теста.
Конечное состояние. Состояние объекта после прохождения теста.
Ввод. Любой способ, при помощи которого данные могут быть доставлены объ­
екту. Примеры: сохраненные данные, генерируемые данные, нажатие клавиши,
сообщение.
Наблюдаемый. Любое видимое и ожидаемое изменение состояния объекта,
или отсутствие изменений в состоянии объекта, если это изменение не ожидалось.
Примеры: новый экран, неправильные выходные данные, неизменившийся экран.
Итог. Наблюдаемый результат теста. Примеры: изменившийся объект данных,
сообщение, новый экран, изменение состояния, неизменный объект, отсутствие
сообщения, пустой экран. В тестировании мы рассматриваем итог, а не вывод. Это
не семантическое противоречие. То, что экран не изменился, очевидно, является
итогом, но не выводом. Если вы полагаете, что все тесты должны иметь вывод, то
вы упустите множество полезных тестов. Все тесты, однако, должны иметь итог.
Оракул. Любые средства, используемые для предсказания итога теста
[HOWD86].
Проектирование теста. Процесс определения объекта, начального состояния
и ввода, а также прогноз итога теста и/или конечного состояния для данного объ­
екта, начального состояния или ввода.
Тестирование. Проектирование, отладка и выполнение тестов.
Подтест. Наименьшая составная часть теста, включающая в себя объект, на­
чальное состояние, ввод и прогнозируемый итог.
Тест. Последовательность одного или более подтестов, выполняемых после­
довательно. Итог и/или конечное состояние одного подтеста является вводом и /
или начальным состоянием для другого. Термин «тест» обобщает, включает в себя
подтесты, тесты как таковые и тестовые комплекты.
Тестовый комплект. Совокупность одного или более тестов, ориентированных
на один объект с общей задачей и базой данных и используемых, как правило, сов­
местно.
Опровергаемый. Оператор является опровергаемым, если вы можете поставить
эксперимент, который либо подтвердит, либо опровергнет его истинность.
Требования. То, что объект должен выполнять и/или характеристики, кото­
рыми он должен обладать. Выбор требований относительно произволен, но они
должны быть непротиворечивы, разумно полны, реализуемы и, что самое важное,
опровергаемы.
28 Глава 1 • Введение

Характеристика. Желательное поведение объекта; вычисление или оценка,


проводимые объектом. Требования представляют собой совокупность характе­
ристик.
Вариант. Характеристики, представляющие собой совокупность вариантов.
Спецификация. Ясное, как правило, неполное определение требований. В ка­
честве спецификаций могут использоваться документы, список характеристик,
прототип, тестовый комплект. Спецификации обычно незакончены, поскольку
многие требования часто бывают очевидны. Например: «программа не должна
уничтожать или портить данные». Самая большая ошибка, которую может допус­
тить тестировщик, — это предположить, что в спецификациях представлены все
требования.
Проверка соответствия (валидация). Оценка объекта с целью продемон­
стрировать, что он удовлетворяет требованиям. Тестирование —это не единствен­
ный метод проверки соответствия, но в данной книге рассматривается только он
[WALL94],
ИскаженностъК Оценка объекта с целью продемонстрировать, что он не удов­
летворяет требованиям.
Критерии соответствия (валидации). Средства для демонстрации того, вы­
полняются или нет требования. Например, прямое сравнение с предсказанны­
ми значениями, сравнение в пределах определенных областей значений, наблюда­
емая последовательность событий.
Сравнение итогов. Предсказанный и фактический итоги теста сравниваются по
определенным критериям соответствия.
Сценарий теста. Документ, программа или объект, которые для каждого тес­
та и подтеста в тестовом комплекте определяют тестируемый объект, требование
(обычно условие), начальное состояние, вводы, ожидаемый итог и критерии соот­
ветствия.
Симптом (отказ IEEE94). Наблюдаемое аномальное поведение любого объек­
та (не обязательного тестируемого), такое как несоответствие требованиям или
возникновение незапланированных явлений.
Ошибка (сбой IEEE94). Просчет в проектировании, ведущий к возникновению
симптомов у какого-либо объекта (тестируемого и не только) при прохождении
этим объектом определенного теста.
Тест считается пройденным, если при корректно заданных критериях соответ­
ствия после его прохождения фактический итог совпадает с предсказанным и от­
сутствуют симптомы.
Тест считается не пройденным, если после его прохождения фактический итог
не совпадает с предсказанным и/или присутствуют симптомы. Причиной этого
может быть использование неверного объекта, неверный ввод, неверный прогно­
зируемый итог, неверное начальное состояние, неверные критерии соответствия,
некорректное применение этих критериев, ошибка при проектировании теста,

1 Автор использует свою собственную, оригинальную терминологию. Отдавая дань классику, от­
метим, что более распространены следующие термины: верификация — проверка того, что программа
правильно реализует определенную функцию; валидация — проверка того, что программа соответству­
ет требованиям заказчика. — Примем, иауин. ред.
1.2. Основные термины 29

ошибка в выполнении теста, ошибка в процессе проверки соответствия и даже, ка­


ким бы это не могло показаться странным, ошибка в тестируемом объекте.
Протестирован. Объект считается (успешно) протестированным, если вы­
полнены все запланированные тесты, без появления симптомов, это означает, что
все тесты были пройдены. Если не указано обратное, «протестирован» означает —
успешно протестирован.
Свободен от ошибок. Мы говорим, что объект «свободен от ошибок», если мы
считаем, что вероятность появления у него симптомов или возникновения спрово­
цированных им симптомов у других используемых объектов достаточно мала, что­
бы гарантировать успешное использование этого объекта. Идея абсолютной «сво­
боды от ошибок» является неопровергаемой, а значит, не может быть требованием.
Случайная корректность. Успешное прохождение всех тестов еще не означает,
что объект свободен от ошибок. Несмотря на то, что фактический итог совпадает с
предсказанным, в программе могут быть ошибки, поскольку совпадение итогов мо­
жет быть случайным. Например, если программа должна вычислять у:=х2, но ошиб­
ка в программировании приводит к тому, что вычисляется у:=2х, а входное значе­
ние х в тесте оказывается равным 2, то итог будет равен у=4, несмотря на ошибку.
Про тестируемую таким образом программу говорят, что она случайно корректна.
Слепота (сокрытие, утаивание). Для любого метода тестирования (за исклю­
чением тестирования всех возможных вводов и начальных состояний) существу­
ет определенный тип ошибок, к которым он слеп. Например, множество методов
слепо к случайной корректности.
Модуль. Наименьший элемент, подлежащий тестированию. Этот элемент
(обычно) является продукцией одного программиста и представляет собой на­
именьший компилируемый сегмент программы, такой как подпрограмма. Модуль
как объект тестирования обычно не включает в себя подпрограммы, вызываемые
им функции, фиксированные таблицы и так далее.
Тестирование модуля. В тестировании модулей принято, что вызываемые под­
программы и вызовы функций считаются компонентами языка (например, клю­
чевыми словами). Вызываемые и вызывающие компоненты считаются либо ра­
ботающими корректно, либо заменяются имитаторами. Тестирование модулей
обычно является задачей их разработчиков.
Ошибка модуля. Ошибка, которая, скорее всего, будет выявлена при грамотном
тестировании модуля.
Модуль является компонентом. Компонент представляет собой совокупность
одного или более компонентов, которая может тестироваться как единое целое.
Например, модуль, подпрограмма, функция, макрос, программа и подпрограм­
мы, которые она вызывает, связанные процедуры и целые системы программного
обеспечения.
Интерфейс между компонентами — любые средства, при помощи которых
данные могут передаваться или совместно использоваться. Это может быть вы­
зов подпрограммы, общий объект данных, глобальные данные, физический интер­
фейс, сообщение.
Тестирование интеграции: Тесты, направленные на проверку взаимодейс­
твия и совместимости компонентов, успешно прошедших свои тесты. То есть
30 Глава 1 • Введение

компоненты А и В, которые прошли тесты компонентов, объединяются в новый


компонент С = (А, В). Тестирование интеграции направлено на проверку согла­
сованности получившейся совокупности. Интересующее нас поведение совокуп­
ности обычно исследуется с помощью интерфейса между компонентами.
Ошибка интеграции. Ошибка, которая, скорее всего, будет выявлена при гра­
мотном тестировании интеграции.
Интеграция. Процесс тестирования интеграции, отладки интерфейса и ис­
правления ошибок интеграции. Интеграция может изменить характер поведения
и тем самым привнести новые ошибки. Интеграция обычно производится созда­
телем компонентов, если за связываемые компоненты ответственен один человек.
Зачастую ее независимо выполняет отдельный интегратор, если в создании ком­
понентов участвовало несколько человек.
Тестирование компонента. Тестирование компонента отличается от тестирова­
ния модуля тем, что оно включает в себя тестирование вызываемых компонентов
и объектов данных. Например, тестирование процедуры совместно с вызываемыми
ею подпрограммами, тестирование процедуры и фиксированной таблицы данных.
Разумное тестирование компонента подразумевает предварительную успешную ин­
теграцию подчиненных компонентов и модулей и тестирование интеграции этих
компонентов. В отличие от тестирования компонентов при тестировании модулей
модуль когда-нибудь составит единое целое с относящимися к нему компонентами.
Ошибка компонента. Ошибка, которая, скорее всего, будет выявлена при тес­
тировании компонента.
Системы программного обеспечения. Совокупность компонентов, такая, что
определенные требования могут быть проверены, даже если некоторые компонен­
ты отсутствуют или не подвергались тестированию.
Тестирование системы производится для проверки поведения системы, которая
не может быть выполнена путем тестирования модулей, компонентов или тестиро­
вания интеграции. Например, тестирование, производительности, инсталляции, це­
лостности данных, управления памятью, безопасности, надежности. В идеале тести­
рование системы предполагает, что все узлы были заранее успешно интегрированы.
Тестирование системы часто осуществляется независимыми тестировщиками.
Ошибка производительности. Ошибка, главным симптомом которой является
неудовлетворительная или заниженная производительность (например, низкая
пропускная способность или увеличение задержки).
Ошибка безопасности. Ошибка, увеличивающая риск несанкционированного
проникновения в систему, что позволит просматривать или изменять файлы, не
обладая соответствующими правами.
Ошибка потери ресурсов. Ошибка, ведущая к потере динамически размеща­
емых ресурсов, таких как оперативная память или место на диске.
Системная ошибка. Ошибка, вероятность обнаружения которой путем тести­
рования модулей, компонентов или интеграции мала. Ошибка, проявляющаяся
в поведении не отдельных компонентов, но системы целиком. Например, ошибка
производительности, ошибка безопасности, ошибка потери ресурсов.
Модули, подпрограммы, программы, подсистемы. Приблизительные названия
компонентов, расположенные по мере явного возрастания их размера.
1.3. О тестировании 31

Окружение. Совокупность аппаратных, программных средств и данных, в ко­


торых и посредством которых компоненты создаются, тестируются и использу­
ются. Сюда входят (но этим перечень не ограничивается) вызывающие и вызыва­
емые компоненты, операционная система, аппаратные средства, компилятор,
ваши средства тестирования (разумеется) и прочее, что может влиять на работу
компонентов или зависеть от нее.

1.3. О тестировании
1.3.1. Тестировщик и программист
Повсюду в этой книге мы будем упоминать и противопоставлять друг другу «тес­
тировщиков» и «программистов» так, как будто они являются разными людьми.
Такое разделение может привести вас к мысли, что тестирование методом черно­
го ящика предназначено только для независимых тестировщиков, но не для про­
граммистов. Другим ошибочным мнением является то, что я сторонник идеи, что
тестирование и программирование должны выполняться различными людьми,
(то есть должно проводиться независимое тестирование). Я хочу предотвратить
и/или скорректировать такие ошибочные взгляды.
Говоря образно, программист должен носить две шляпы — шляпу програм­
миста и шляпу тестировщика. Когда он выполняет тестирование, он должен на­
деть шляпу тестировщика и думать как тестировщик. Вот что представляет собой
«тестировщик», для которого я пишу эту книгу. Итак, тестировщик может быть,
а может и не быть тем же самым человеком, который пишет программы. Так как
способ мышления при программировании и способ мышления при тестировании
сильно отличаются, хорошая идея — просто рассказать о двух ролях, как будто
бы их играют различные люди. Способ мышления в программировании известен
давно и существует много книг по этой теме, поэтому не стоит специально на этом
останавливаться. Способ мышления, применяемый при тестировании, возник от­
носительно недавно, и именно поэтому эти способы сильно различаются. Методы
тестирования, затрагиваемые здесь, предназначены как для независимых тести­
ровщиков, так и для тех программистов, которые в данный момент тестируют свое
или чье-либо программное обеспечение.

1.3.2. Почему мы тестируем программное обеспечение?


Для проведения тестирования программного обеспечения есть несколько весо­
мых причин.
1. Обеспечение программистов информацией, которую они смогут использо­
вать для предотвращения ошибок.
2. Обеспечение менеджеров информацией, которая необходима им для разум­
ной оценки риска при использовании объекта.
3. Создание объекта, максимально свободного от ошибок.
32 Глава 1 • Введение

4. Создание проекта, поддающегося тестированию, то есть проекта, который


можно легко проверить на соответствие, на искаженность и который будет
легко сопровождать.
5. Проверка искаженное™ объекта с помощью как сформулированных, так
и не сформулированных требований [MYER79]. Это еще называют «взло­
мом программного обеспечения».
6. Проверить соответствие объекта (убедиться в его действенности), то есть
показать, что он работает правильно.
Информация, необходимая для выполнения пункта 2, определяется степенью,
до которой объект действует правильно (то есть количеством подтестов, пройден­
ных и не пройденных), и некоторыми рамками, в пределах которых объект не мо­
жет быть искажен. То есть пределом, до которого объект не взломай, и пределом,
до которого он работает. Тот предел, до которого объект считается свободным от
ошибок, является также границей, до которой он соответствует требованиям и не
искажен. Таким образом, у нас есть три основных задачи: хорошее проектирова­
ние, искаженность, проверка соответствия.
Все, что пишут люди, содержит ошибки. Проведенное тестирование чего-либо
не является эквивалентом утверждения, что это что-то свободно от ошибок.
Программист не может думать обо всем —в особенности обо всех возможных вза­
имодействиях между различными характеристиками и между различными час­
тями программы. Мы пытаемся взломать программу, так как только такой путь
обеспечит нас уверенностью в том, что продукт готов к использованию.
Другая задача тестирования —это накопление информации для менеджмента.
При наличии необходимой информации и достаточного количества тестов мы мо­
жем с достаточной уверенностью утверждать, что программа готова к использо­
ванию. В конечном счете это как раз то, за что платят тестировщикам, — помощь
в создании полезной программы.
Наивысшая цель тестирования — это обеспечение качества: накопление ин­
формации, которая, вернувшись к программисту, поможет избежать ему прошлых
ошибок и улучшить качество программного обеспечения в будущем.
Грязный тест (или негативный тест): тест, первичной целью которого явля­
ется проверка искаженное™; то есть тест, предназначенный для того, чтобы взло­
мать программу.
Чистый тест (или позитивный тест): тест, первичной целью которого явля­
ется проверка соответствия; то есть тест, предназначенный для того, чтобы проде­
монстрировать корректную работу программы.
Тест является действенным, если в результате его выполнения выявляются
симптомы существующих ошибок.
В спецификациях обычно указываются только те требования, которые должны
быть проверены на соответствие (то есть на то, что объект должен делать), и не со­
держатся требования, которые должны быть проверены на искаженность (то есть
на то, что объект не должен делать). Так как количество действий, которые объ­
ект должен выполнять, конечно, а количество действий, которые объект не дол­
жен выполнять, не ограничено, из общих соображений можно предположить, что
1.3. О тестировании 33

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

1.3.3. Стратегия тестирования


Стратегия тестирования, или методы тестирования —это систематические ме­
тоды, используемые для отбора и/или создания тестов, которые должны быть
включены в тестовый комплект. Это могут быть случайные вводы, тест, направ­
ленный на проверку моих подозрений, тест, направленный на проверку ваших
подозрений, тест, направленный на проверку соответствия требованиям, тест,
направленный на проверку искаженности; тесты, который мы выполняли пос­
ледний раз, тесты, которые отличаются от тестов, которые мы выполняли послед­
ний раз. Мы выбираем стратегию, такую, что существуют правила, по которым мы
можем определить, удовлетворяет данный тест стратегии или не удовлетворяет.
В принципе, стратегия должна быть программируемой.
Стратегия является эффективной, если тесты, включенные в нее, с большой ве­
роятностью обнаружат ошибки тестируемого объекта. Эффективность стратегии
зависит от комбинации природы тестов и природы ошибок, на поиск которых эти
тесты направлены. Как на войне и в бизнесе, здесь существуют эффективные и не­
эффективные стратегии. Более того, так как объект изменяется с целью исправле­
ния ошибок и увеличения его возможностей, типы ошибок, находимые у объекта,
меняются со временем, и, следовательно, меняется эффективность стратегии. В то
время как теоретически возможно, что стратегия по отношению к специфическим
объектам совершенствуется во времени, на самом деле эффективность большин­
ства стратегий со временем убывает.
Стратегия поведенческого теста основана на технических требованиях.
Например: тест всех характеристик, упомянутых в спецификации, выполнение
всех грязных тестов, вытекающих из требований. Тестирование, выполняемое с
помощью стратегии поведенческого теста, называется поведенческим тестиро­
ванием. Поведенческое тестирование называется также тестированием черного
ящика. Для поведенческого тестирования также используется термин функцио­
нальное тестирование'. При поведенческом тестировании (в принципе, но не на
практике) не обязательно знать, как объект сконструирован. Тема этой книги —
поведенческое тестирование (тестирование черного ящика).
Стратегия структурного теста определяется структурой тестируемого объек­
та [BASI87, BEIZ90, NTAF88, OSTR96], Например: выполнение каждого операто­
ра по меньшей мере один раз, выполнение каждой ветви но меньшей мере один раз,
тестирование использования всех объектов данных, выполнение каждой команды12

1 Термин «функциональное тестирование» обычно используется в литературе, по на практике


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

2 Зак 770
34 Глава 1 • Введение

объектной программы, полученной при компиляции. Тестирование, выполненное


с помощью стратегии структурного теста, называется также тестированием про­
зрачного ящика или тестированием белого ящика. Стратегия структурного теста
требует полного доступа к структуре объекта —то есть к исходному коду. Эта кни­
га только поверхностно затрагивает методы структурного тестирования.
Стратегия гибридного теста является комбинацией поведенческой и структур­
ной стратегий [CLAR76, RICH81], Поведенческая, структурная и гибридная стра­
тегии не противоречат друг другу, и ни про одну из них нельзя сказать, что она луч­
ше других. Модули и низкоуровневые компоненты часто тестируются с помощью
структурной стратегии. Большие компоненты и системы в основном тестируются с
помощью поведенческой стратегии. Гибридная стратегия полезна на всех уровнях.
Не существует лучшей стратегии, так как полезность стратегии зависит от приро­
ды тестируемого объекта, природы ошибок объекта и уровня ваших знаний.

1.3.4. Парадокс пестицида1


Большинство из нас предпочитают доделать дело до конца. Знать, что работа вы­
полнена, выполнена правильно, и в подходящее время взять следующее задание.
Тестирование программного обеспечения на это не похоже. Если вы хорошо сделали
работу по выявлению ошибок и если люди из отдела обеспечения качества хорошо
выполнили работу по передаче ваших исследований обратно программистам, то они,
скорее всего, не повторят прошлых ошибок. Хороший программист, если у него есть
время и необходимые ресурсы, обычно изучает проблемы, выявленные тестировщи­
ками (или им самим), обобщает идеи и затем исследует свое программное обеспече­
ние на предмет выявления и исправления в нем таких же или подобных ошибок.
Все методы тестирования имеют встроенные допущения о природе ошибок.
Каждый метод тестирования нацелен на определенный набор ошибок. Если про­
граммист реагирует на результаты тестирования и информацию об ошибках со­
кращением и удалением этих ошибок, из этого следует, что его программа улуч­
шается, а эффективность предыдущих тестов постепенно уменьшается. То есть
ваш тест устаревает и вам приходится изучать, создавать и использовать новые
тесты, основанные на новых методах отслеживания новых ошибок.

1.3.5. Природа и причины ошибок


Обратитесь к [BEIZ90] и [ANSI94] для подробного обсуждения ошибок и катего­
рий ошибок. Главная причина, почему я использую термин «ошибка», а не офици­
альный термин «дефект», это то, что «дефект» подразумевает, что кто-то должен
нести за него ответственность. Предполагается недостаток добросовестности про­
граммиста, леность или некомпетентность. Ошибки, сделанные компетентным
программистом, работающим на современном программном обеспечении, в соот-

' Это называется «парадокс пестицида» по аналогии с явлением в сельском хозяйстве, когда ли­
чинки долгоносика, приспособившись к яду, вынуждали нас создавать все более мощный яд, который
приводил к возникновению все более устойчивых к этому яду личинок, пли искать принципиально
иное решение.
1.3. О тестировании 35

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


ми (надеюсь, вы не будете обвинять нас в излишней мягкости).
В хорошем, продуманном программном обеспечении источником ошибок яв­
ляются сложность и ограниченная способность людей к борьбе со сложностью, а
не тупость. Чем лучше программный процесс, тем менее вероятно, что ошибки, ко­
торые сохраняются в течение поведенческого тестирования, являются ошибками
конкретных программистов. Большинство ошибок, которые мы находим при помо­
щи поведенческого тестирования в хорошо разработанном, качественном програм­
мном обеспечении, являются следствием непредсказуемого взаимодействия между
компонентами или между объектами, или результатом непредсказуемых побочных
эффектов, вызываемых совершенно невинными, на первый взгляд, процессами.
Если ошибки, найденные в результате поведенческого тестирования, — про­
стые и их легко распределить по категориям, это говорит о том, что неудовлетво­
рителен технологический процесс, а не программист. Мы принимаем на веру, что
программист хорЬшо обучен, обладает надлежащими инструментами и компетен­
тен1. Это называется «гипотезой компетентного программиста». Так как человек,
который проводит поведенческое тестирование, не обязательно является тем же
самым человеком, который пишет программное обеспечение, важно иметь в виду
эту гипотезу, считая, что человеческие недостатки и неприязнь не вторгаются в
процесс программирования.
Полезны три широкие категории ошибок: ошибки модулей/компонентов,
ошибки интеграции и системные ошибки, названные так в соответствии с той фа­
зой разработки, в которой, вероятнее всего, могут быть найдены ошибки.
Ошибки модулей/компонентов найти и избежать легче всего. Когда мы тести­
руем систему и тест выявляет ошибку, мы не можем сказать, что явилось этому
причиной, —ошибка модуля, ошибка интеграции или системная ошибка. Это мы
узнаем только после того, как ошибка будет устранена. Так как системное тести­
рование требует гораздо больших ресурсов, чем тестирование модулей/компо-
иентов, выявление ошибок модулей, оставшихся к моменту начала системного
тестирования, представляет собой напрасную трату сил. Таким образом, задачей
тестирования модулей/компонентов является сокращение числа ошибок, кото­
рые переходят в последующие стадии процесса.
Ошибки интеграции более трудны для выявления и предотвращения, так как
они возникают при взаимодействии между компонентами, которые являются
корректными сами по себе. Взаимодействие компонентов подчиняется законам
комбинаторики, что означает, что их число растет как п2(как квадрат числа задей­
ствованных компонентов) или даже хуже (например, как п! — факториал числа
компонентов). Цель тестирования интеграции — убедиться в том, что когда мы
переходим к системному тестированию, некорректных взаимодействий между
компонентами совсем не осталось или осталось мало.
Системное тестирование — это качественно новый уровень тестирования.
Даже если все особенности были проверены при тестировании модулей/компо­

1 Если некомпетентный программист нс может стать компетентным, избавьтесь от него. Если про­
цесс содержит ошибки, исправьте его. Ни от кого нельзя ожидать продуктивности без надлежащих
инструментов.
36 Глава 1 • Введение

нентов или при тестировании интеграции, нам следует включить поведенческое


тестирование как составную часть системного тестирования. При тестировании
модулей/компонентов или интеграции то, что мы тестируем, имеет детерминиро­
ванное поведение. При системном тестировании у пас, однако, возникают допол­
нительные трудности, связанные с многозадачностью. Следовательно, порядок,
в котором будут возникать те или иные ситуации, уже не может быть с уверенно­
стью предсказан. Такая неопределенность и проблема синхронизации являются
богатой почвой для более сложных ошибок. Основная цель системного тестиро­
вания —убедиться в том, что в недетерминированном мире программное обеспе­
чение ведет себя так же предсказуемо, как и в детерминированном мире.

1.3.6. Когда надо остановиться


Процесс тестирования потенциально бесконечен, как с теоретической, так и с
практической точки зрения. Тем не менее, даже зная, что ошибки остались, мы
должны завершить тестирование, так как если мы этого не сделаем, все усилия
будут напрасны. Если у нас есть большое количество опытных данных, то можно
создать статистическую модель, которая даст нам понимание того, насколько рис­
кованно прекратить тестирование и предложить программу для коммерческого
использования [HAML94, М115А90].Если вы почувствовали некоторую осторож­
ность моей формулировки, запомните это, так как обоснованность таких моделей
не очевидна и не бесспорна. Тем не менее, прогресс не стоит на месте, и большинс­
тво полезных моделей нуждаются в информации, которую мы собираем при тес­
тировании, особенно в ходе системного тестирования, и которая является частью
данных, используемых для определения момента завершения тестирования.

1.3.7. Тестирование черного ящика — это еще не все


Тестирование поведения, это еще далеко не все, что мы должны сделать. Одного
тестирования мало. Если мы рассматриваем все тестирование, которое мы можем
и должны провести с программой, от начала и до конца, поведенческое тестирова­
ние занимает 35-65% от общего времени1. Относительная полезность поведенче­
ского тестирования зависит от проекта. Если в проекте все характеристики жес­
тко запрограммированы с использованием специальной логики, то структурные
методы превалируют. Когда проект основан на использовании общих алгорит­
мов, чье специфическое поведение определяется при помощи таблиц данных или
параметров вызова, то преобладает поведенческое тестирование. Важность пове­
денческого тестирования подобна важности различных методов навигации. Что
именно является наиболее важным, зависит от погоды, от близости берега, от того,
какими приборами вы располагаете, и так далее. Нам следует прислушаться к мо­

’ В объектно-ориентированном программировании увеличивается важность поведенческого тести­


рования. Ясно, что методы поведенческого тестирования будут более важны для создания программ­
ного обеспечения при помощи надежной библиотеки многократно используемых объектов, чья вну­
тренняя работа и структура сознательно от нас скрыты; ведь нам, возможно, придется проводить гораз­
до больше тестов, для того чтобы быть уверенными в надежности объектов | BERA94, NORT94J.
1.3. О тестировании 37

ему любимому автору Натаниелю Боудичу [BOWD77]: «Мудрый штурман ни­


когда не полагается только на один метод».

1.3.8. Тестирование — это еще не все


Ошибки, обнаруженные в процессе тестирования, должны нас, с одной стороны,
радовать, с другой стороны —огорчать. Радовать, так как это означает, что на одну
проблему стало меньше; огорчать, поскольку это указывает на несовершенство на­
шего процесса разработки программного обеспечения. Радовать, так как мы узна­
ли, как усовершенствовать процесс и предотвратить подобные проблемы в буду­
щем. Мы создаем программы около 40 лет, и наиболее важный урок, который мы
усвоили, звучит следующим образом: «Делайте это как можно раньше!»
Чем раньше ошибки найдены и исправлены, тем дешевле обходится их исправ­
ление. Усилия, затрачиваемые до начала проектирования, меньше, чем усилия, за­
трачиваемые в течение проектирования. Усилия, затрачиваемые до начала напи­
сания кода, меньше, чем усилия, затрачиваемые после написания кода. Усилия,
затрачиваемые на тестирование модулей, меньше, чем усилия, затрачиваемые на
системное тестирование, которые, в свою очередь, меньше усилий, затрачиваемых
после инсталляции программы. Ниже приводится несколько эффективных мето­
дик, не связанных с тестированием, приблизительно в том порядке, в котором они
должны применяться.
Создание прототипа. Прототипом программы является урезанная реализа­
ция, которая имитирует то поведение программы, которое необходимо пользова­
телю [STAK89], Цель этого —дать нечто осязаемое пользователю, чтобы он мог
нам сказать, является ли полезным для него то, что мы создаем, будет ли он это
впоследствии покупать. Прототип на самом деле не обязан работать и обычно не
работает. Мы создаем программное обеспечение для пользователей. Привлечение
их к процессу как можно раньше является эффективным подходом, позволяющим
избежать грубых промахов.
Анализ требований. Требования задают содержание проектирования [YEH R80].
Если требования несовместимы, то проектирование не может быть корректным.
Анализ требований означает проверку требований на логическую непротиворечи­
вость, тестируемость, легкость реализации. Мы не можем ожидать, что пользова­
тель обеспечит нас адекватными требованиями, так как он не умеет этого делать.
Мы все были бы похожи на машину, которая, не загрязняя окружающую среду,
проезжает 100 километров на литре воды, везет 12 взрослых людей и помещается
на стоянке 3 х 2 м. Мы все были бы похожи на «Мерседес» по цене «Запорожца».
Нашей целью как создателей программного обеспечения не является сделать не­
возможное и удовлетворить все капризы пользователей. Нашей целью является
разработка продукта, соответствующего своей цене.
Формальный анализ [ANDE79, ВАВЕ94, HANT76, WING94]. Мы не можем
тестировать все, да и нет в этом необходимости . Это особенно справедливо в слу­
чае поведенческого тестирования. Множество вещей, которые мы не можем на
практике протестировать в настоящее время (и вряд ли когда-нибудь сможем),
включает в себя все возможные способы взаимодействия характеристик друг с
38 Глава 1 • Введение

другом. Тестирование поведения программы при каждом возможном варианте


инсталляции, является другой неосуществимой задачей. То же самое относится к
взаимодействию между нашим пакетом программ и другими пакетами, проверке
защищенности нашей программы, некоторым коммуникационными протоколам
и множеству алгоритмов. Всякий раз, когда по ряду причин сложность тестиро­
вания увеличивается быстрее, чем сложность самого тестируемого объекта, фор­
мальный анализ, возможно, математический, является предпочтительнее тести­
рования. Мы, однако, нуждаемся в тестировании, чтобы убедиться, что сам наш
анализ в должной мере свободен от ошибок1.
Проектирование. Хороший проект имеет мало ошибок и легко тестируется.
Намного легче спроектировать что-то, что не может быть протестировано, чем
что-то, поддающееся тестированию. Намного легче спроектировать что-то, что со­
вершенно невозможно сопровождать, чем спроектировать что-то, что возможно.
Самые грамотные требования сводятся на нет непродуманными проектами, про­
верить которые невозможно при помощи конечного числа тестов.
Формальное инспектирование [FAGA76, GILB93, WEIN90] является пер­
вичным методом предотвращения ошибок, и это неоднократно подтверждалось.
Процесс разработки программного обеспечения, который не включает в себя фор­
мальное инспектирование, очевидно дефектен, и устранение ошибок в нем намно­
го больше зависит от тестирования.
Самотестирование. Тестирование, выполняемое самими программистами, го­
раздо более эффективно, чем тестирование, выполняемое кем-то еще. То же самое
относится к тестированию группой, производящей данное программное обеспе­
чение. Аналогично тестирование в организации, разрабатывавшей программное
обеспечение, эффективнее, чем внешнее тестирование (то есть бета-тестирование)
того же самого программного обеспечения. Это не отвергает идеи, что независи­
мое тестирование может быть действенно, так как эффективность —не единствен­
ный критерий, определяющий, кому и какое тестирование проводить.
Если независимый тестировщик повторяет тест, ранее выполненный разработ­
чиком, или просто выполняет тестирование, которое следовало бы выполнить во
время разработки, в этом случае независимое тестирование совсем не приносит
никакой информации, фактически не имеет смысла. Такое тестирование (незави­
симое повторение тестов разработчика) может быть полезно, только если разра­
ботчик некомпетентен или предумышленно делает не все корректно. А это проти­
воречит нашей гипотезе о компетентности программиста.
Цель независимого тестирования — обеспечить различные ракурсы, следова­
тельно, различные тесты; более того, проводить эти тесты в среде с более широкими
возможностями (и поэтому более сложной и дорогой), чем это доступно разработ­
чику. Цель самотестирования —удалить те ошибки, которые могут быть найдены

' Все, что мы делаем в процессе разработки программного обеспечения, подвержено ошибкам.
Формальное (то есть математическое) доказательство корректности алгоритма точно так же уяз­
вимо для ошибок, как любой другой процесс, выполняемый человеком. Убедиться в этом легко: д о ­
статочно вспомнить о количестве статей в математических журналах, озаглавленных: «Контрпример
к теореме...».
1.4. Процесс разработки программного обеспечения 39

посредством малых затрат в простейшей детерминированной среде путем тестиро­


вания модулей/компонентов или низкоуровневого системного тестирования.
Инструменты. Мы считаем исходные синтаксические ошибки кода просто по­
мехами, так как у нас есть инструменты (компиляторы), которые находят такие
ошибки гораздо лучше, чем мы сами. В наших языках программирования и ком­
пиляторах к настоящему времени появились совершенные детекторы ошибок, ав­
томатизировавшие то, что когда-то являлось сложной для человека задачей. Если
ошибка может быть определена (и/или исправлена) автоматически, это должно
быть сделано. Не пытайтесь отключать автоматизацию и инструменты, выявля­
ющие ошибки. Исключить надо как раз подверженную ошибкам ручную обработ­
ку кода, тогда, когда доступна автоматизация. Существует все более увеличиваю­
щаяся разница между инструментами, которые в действительности используют
программисты и тестировщики, и инструментами, которые разрабатывают для
них исследователи. Ликвидируйте этот разрыв! Он стоит того. Это окупится.
\ Мы, как тестировщики, должны всегда стремиться к тому, чтобы можно было
вообще обойтись без тестирования. Это наша недостижимая цель. Тестирование
является контролем качества. Обеспечение качества означает предотвращение
ошибок. Всегда выгоднее предотвратить ошибки, чем их потом находить. Но эта
цель недостижима, так как история показывает, что автоматизация процесса и
предотвращение предыдущих ошибок являются предпосылками к встрече со все
более сложными задачами, которые ставят перед нами нужды пользователей.
Наш текущий технологический процесс (каким бы несовершенным он ни был)
является более совершенным, чем технологический процесс, использовавшийся
всего десятилетие назад. Мы уже не программируем так, как это делали десять лет
назад, но мы пишем новые программы, несущие в себе все более сложные ошибки.
Наши пользователи повышают свои требования к качеству, а, следовательно, рас­
тут требования к нашим возможностям и методам тестирования.

1.4. Процесс разработки


программного обеспечения
1.4.1. То, что на самом деле важно
Наиболее важные моменты, касающиеся разработки программного обеспече­
ния, легко перечислить. Нам необходим процесс. Процесс должен быть понятен.
Процессу должны следовать.
Процесс. Я убежден, что процесс используется в любом случае, поскольку даже
хаос в своем роде является процессом. Наличие процесса означает, что существу­
ет возможность предсказать, что будет происходить с программным продуктом
на следующем шаге. Такая предсказуемость возникает, когда появляется потреб­
ность в данном продукте, и завершается, когда продукт устаревает.
Наличие процесса еще не означает существования детально разработанной для
него документации. Ряд наилучших проектов на моей памяти имели крайне огра­
ниченный объем документации. И наоборот, когда меня спрашивают о том, что
40 Глава 1 • Введение

необходимо иметь, я ссылаюсь на подробно задокументированное описание про­


цесса, оставшееся после одного из самых крупных провалов из тех, что мне доводи­
лось видеть. Объем формальной документации для конкретного проекта напрямую
зависит от размера этого проекта. Документы (если они читаются) —это наиболее
эффективный способ донести детали проекта до человека, не разбирающегося в
данном процессе и в предпосылках к проекту. Контролировать процесс, а значит
обеспечить его качество обычно проще, если шаги в процессе задокументированы.
Он понятен. Если процесс непонятен тому, кто должен его понимать, то этому
процессу невозможно следовать. Понимания можно добиться, читая документа­
цию, если только людям дается время па осознание и суммирование того, что они
прочли. Может в этом помочь и видео. Обучение общим методам работы с процес­
сами лишено смысла, поскольку портят дело обычно специфические особенности,
а не общие закономерности. Вам будет необходимо освоить особенности некото­
рого конкретного процесса.
Ему следуют. Наличие понятного процесса еще не означает, что ему будут сле­
довать. Индикатором того, что в процессе возникли проблемы, служит возник­
новение расхождения между формальным процессом (то есть задокументирован­
ным процессом) и тем, что фактически делают люди. В таких случаях я встаю на
сторону программистов и тестировщиков, идущих своим путем, а не тех умников,
которые этот процесс придумали. Если процесс игнорируют, то это, скорее всего,
потому, что он не работает, а не потому, что программисты — закостенелые рет­
рограды. Большинство людей, хотя и не все, если им указать более эффективный
способ сделать что-либо и обеспечить инструментами и навыками, необходимы­
ми для работы, будут следовать этому новому пути. Процессом перестают руко­
водствоваться в случае, если он ущербен, если существуют преграды для его ис­
пользования или если не хватает необходимых ресурсов (то есть навыка, времени,
инструментов).

1.4.2. Десять(16) и одна заповедь управления процессом


В таком разделе во множестве разных книг вы можете найти тщательно разрабо­
танные наборы блок-схем процедур с таинственным образом обозначенными пря­
моугольниками и стрелками различных видов и стилей, входящими в эти прямо­
угольники и выходящими из них во всех направлениях. Я не собираюсь здесь этого
делать, поскольку усвоил одно еретическое правило: блок-схемы и модели про­
цесса ничего не значат. Они ничего не значат, поскольку провал или успех процес­
са разработки программного обеспечения никоим образом не определяются мо­
делью данного процесса. Культурные, этнические, прикладные и национальные
особенности оказывают гораздо большее влияние на процесс, нежели грандиоз­
ные теории процессов. Утверждение «Процесс А лучше процесса Б» равносильно
утверждению «Японский язык лучше тагальского». Говорить, что рецензирование
предварительного проектирования должно предварять кодирование, то же самое,
что говорить: «В предложении глаголы должны идти впереди существительных».
Специфические особенности языка, а также порядок слов очень важны для гово­
1.4. Процесс разработки программного обеспечения 41

рящего на этом языке, а также для тех, кто занимается переводами с одного языка
на другой, но не они определяют способность носителя языка к общению.
Итак, мы не будем рассматривать модель водопада [ROYC70] или спиральную
модель [ВОЕН86], пошаговую детализацию, нисходящую стратегию, восходящую
стратегию и все такое прочее. Ниже приводятся составляющие, которые вам надо
искать в любом эффективном процессе, подобно тому, как вы ищете существитель­
ные, глаголы и другие части речи в разговорном языке, но без указания, в каком по­
рядке они должны быть скомпонованы, чтобы получился осмысленный процесс.
Дорожная карта процесса. Необходимо понимать в каждый момент времени,
на какой стадии процесса находитесь вы и ваша программа. Если вы предпочита­
ете блок-схемы процесса — это очень хорошо, но некоторые люди отдают пред­
почтение комментариям и спискам. Грамотная дорожная карта процесса разби­
вает процесс на элементарные шаги, которые легко понять и контролировать. Она
достаточно детальна, чтобы вы или кто-нибудь другой мог легко сориентиро­
ваться в ней, но эта детализация не чрезмерна и не подавляет индивидуальность
и творческое начало.
Управление процессом. Управление процессом не подразумевает жесткого со­
блюдения детально расписанного графика, как не означает оно и тоталитаризма
и подавления индивидуальности. Управление процессом подразумевает наличие
эффективных механизмов, при помощи которых все участники процесса могут
получать информацию, касающуюся улучшения тех частей процесса, в которых
они напрямую задействованы. Управление процессом включает в себя обратную
связь, обучение и широкий круг возможностей, и направлено на создание атмо­
сферы в коллективе, в которой люди будут стремиться улучшить себя, свой про­
дукт и мир вокруг.
Количественные измерения и метрики. Мы имеем дело с инженерной на­
укой, а не с искусством, и потому объективность —требование, необходимое для
управления процессом. В инженерной науке количественные измерения являют­
ся залогом объективности. В компьютерных науках количественные измерения
опираются главным образом на метрики [BERL94, FENT91, GRAD87, GRAD92,
MOLL93, ZUSE90, ZUSE94].
Контроль конфигурации так же стар, как Имхотеп, великий строитель пирамид.
Он означает, что в любой момент времени мы можем проверить результат нашего
труда (программу, требования или, скажем, тестовый комплект) и узнать: кто, что,
где, когда, зачем и как. Конфигурация всего, с чем планируется дальше работать,
должна контролироваться, а все, что не контролируется, просто не входит в наш
продукт.
Требования. Что мы создаем? Все в курсе? Все имеют в виду одно и то же? Здесь
я настаиваю на документировании, поскольку человеческая память ненадежна.
Прослеживаемость требований. Откуда взялись требования? Если, как часто
бывает, требования изменяются в процессе разработки программы, на какие дру­
гие требования это повлияет? Прослеживаемость означает, что требования нахо­
дят свое отражение в компонентах программного обеспечения и наоборот. Однако
не требуйте и не ожидайте взаимно однозначного соответствия, так как требова­
ния и компоненты не отображаются в стиле «один к одному».
42 Глава 1 • Введение

Стратегические топкости. Для кого разрабатывается данное программное обес­


печение? Что ожидают заказчики и пользователи от программы, кроме обычной
практичности? Не станет ли эта программа кошмаром для пользователя? Будет ли
она вне конкуренции? Улучшит ли она нашу репутацию? Принесет ли она боль­
шой доход? Будет ли она самой быстрой? Существуют сотни таких стратегических
задач, и руководство определяет относительную важность каждой из них. Без по­
добного руководства (желательно заданного в количественной форме) невозмож­
но определить цели проектирования или понять, когда эти цели достигнуты.
Критерии соответствия требованиям. Как мы узнаем, что продукт удовлетво­
ряет требованиям? Как выбрать объективные критерии соответствия требовани­
ям так, чтобы они были связаны с каждым требованием по отдельности и со все­
ми вместе?
Ответственность. Кто и за что отвечает.
Критерии завершенности. Как узнать, когда данная часть программного обес­
печения (ПО) будет готова к переходу на следующую стадию процесса разработ­
ки? Что является реальным, объективным признаком завершенности?
Критерий готовности. Как узнать, когда данная часть ПО будет удовлетворять
условиям, необходимым для перехода к следующей стадии процесса разработ­
ки? Подобное описание вовсе не избыточно. Компонент программы может прой­
ти через множество стадий или использоваться множеством других компонентов,
каждый из которых имеет свои критерии готовности. Как правило, критерий за­
вершенности компонента является объединением всех критериев готовности для
этого компонента.
Анализ. Анализ — это инженерный процесс, при помощи которого проекти­
рование «наполняется» требованиями (получает полные требования как вход­
ной набор данных). Он может быть полностью интуитивным или полностью фор­
мальным. Интуитивный анализ, зачастую действенный, не может, однако, быть
с легкостью воспринят другими людьми, и, следовательно, какой-либо формаль­
ный, часто математический анализ необходим, даже просто для памяти.
Проектирование. Это все, что касается сути дела, не гак ли? Проектирование
должно предварять программирование или, по крайней мере, проводиться одно­
временно с ним. Инженеры, прежде чем строить, занимаются проектированием,
поскольку это уменьшает риск. Проектные ошибки — это ошибки на бумаге, и
обходятся они гораздо дешевле, нежели сваренная сталь или скомпилированный
код.
Проверка соответствия проекта. Как нам убедиться в том, что проект будет
работать, если мы раньше ничего подобного не разрабатывали? Проверка соот­
ветствия проекта —это совсем не то же самое, что проверка соответствия реализа­
ции проекта. Мосты рушатся из-за плохих, не прошедших проверки проектов, а не
из-за плохих материалов и неквалифицированной рабочей силы. Чем новее про­
ект, тем важнее его проверить перед началом конструирования. Проверка соот­
ветствия производится с помощью моделей, прототипов и инспектирования про­
ектирования.
Программирование. Написание кода в соответствии с проектом и тестирова­
ние его с целью убедиться, что мы создали именно то, что и собирались создать.
1.5. Вопросы для самопроверки 43

Каменщик проверяет горизонтальность своей кладки с помощью уровня, а про­


граммист —с помощью тестов.
Интеграция. Единое целое по своим возможностям существенно больше, чем
сумма отдельных частей. Только у тривиальных, модельных программ уровень
сложности системы эквивалентен сумме уровней сложности ее составляющих.
Архитектор тратит не меньше времени на придание зданию законченного вида,
чем на продумывание шагов по его возведению. Об интеграции не стоит и гово­
рить, если не существует плана интеграции и соответствующих тестов интегра­
ции, будь то объединение двух низкоуровневых подпрограмм или нескольких со­
тен квазиавтономных систем.
Тестирование: Тестирование требуется везде, где работают люди. Тестиро­
вание — это основная составляющая самоуважения и гордости за свое мастерс­
тво. Механик, который не проверяет результат свой работы микрометром, или
негодяй, или дурак. Программист, поиском ошибок которого занимаются впослед­
ствии только другие люди, не уважает себя, за исключением, возможно, странной
гордости за быстрое клепание огромного количества непроверенных и полных
ошибок программ.

1.5. Вопросы для самопроверки


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

2.1. Обзор
Графы рассматриваются как основной концептуальный инструмент тестирования.

2.2. Основные термины


Внешние термины: приложение, массив, конец стрелки, начало стрелки, банко­
мат, двусторонний, ветвь, ошибка, статистика ошибок, вычисление, CASE, код, дан­
ные, означать, D0...WHILE, END, динамическое связывание, время выполнения, выбор­
ка, файл, F0R...D0, функция, IF-THEN-ELSE, входное значение, инспектирование, список,
цикл, меню, опция, модель, мышь, естественный язык, объектно-ориентированное
программирование, путь, платежная ведомость, PRINT, вероятность, шаг обработки,
программа, ветвь программы, программное управление, вход программы, выход
программы, путь программы, оператор программы, программист, язык програм­
мирования, READ, RETURN, экран, программное обеспечение, спецификация, элект­
ронная таблица, оператор, метка оператора, ограничение по памяти, линейный
оператор, подпрограмма, таблица, шаблон, инспектирование теста, модельная
программа, транзакция, TRANSMIT, UNDO, величина, переменная, текстовой редактор.
Внутренние термины: поведенческое тестирование, ошибка, ввод, объект, дей­
ственный тест, спецификация, состояние, тестирование.
Графы —это основополагающий инструмент тестирования. Для тестирования
используются масса различных моделей на основе графов, такие как граф потока
управления, граф потока данных, дерево вызовов, граф конечного автомата, граф
потока транзакций. Прежде всего мы обсудим абстрактные графы, чтобы ознако­
миться с терминологией, которая будет полезна и неизменна при рассмотрении
любых графов.
2.2. Основные термины 45

Отношения: Определенная связь между объектами. Если А и Б — это объек­


ты, a R —отношение, А Й Б означает, что А находится в отношении Й к Б. Чтобы
обозначать отношения, мы будем использовать курсив, например: А связано с Б,
Сэм — отец Билла, А вызывает Б, объект данных А используется для вычисле­
ния значений величин для объекта данных Б; за действием А следует действие Б.
Задача тестирования состоит в том, чтобы убедиться, что все объекты имеют за­
данные отношения друг с другом.
Графы являются набором объектов, отношений между этими объектами и спе­
цификаций (представленных, скажем, в виде списка), указывающих, какие объек­
ты связаны и каким образом.
Узел. Объекты в графах называются узлами. Узлы изображаются окружностя­
ми. Задача тестирования —убедиться, что граф имеет все заданные узлы и не бо­
лее того.

Имя узла. Каждый узел имеет уникальное имя. Если объекты является фай­
лами, имена узлов могут быть именами файлов; если объекты — это программы
или операторы программ, имена узлов могут быть именами программ или метка­
ми операторов соответственно. Ни свойства графа, ни свойства объектов, пред­
ставленных в нем, не зависят от того, какие имена мы дадим узлам.

Вес узла. Узлы могут иметь свойства. Эти свойства называются весом узла.
В этой книге в качестве веса узла мы будем использовать, например: состояние
программы, значение переменной, функцию, которая' описывает, какая из не­
скольких величин может быть использована для вычисления чего-либо, имя дру­
гого объекта. Задача тестирования —убедиться, что узлы с заданным весом имеют
ожидаемый вес.
Связь. Стрелка или линия, которая соединяет узлы, используется для иллю­
страции конкретного отношения между этими узлами. Например, если суть от­
ношения описывается как «А и Б — братья», мы соединяем А и Б линией, что­
бы отметить этот факт. Если в нашей модели определено только одно отношение,
мы можем не надписывать каждую связь, чтобы обозначить это отношение. Если
между объектами может быть несколько отношений, мы можем помечать связи
метками заданных отношений. На рисунке между узлами А и Б существуют два
отношения: 0 — «А и Б —дети одних родителей» и S —«А и Б —друзья». Задача
тестирования —проверить, что все связи находятся там, где и должны находиться,
и что каждой связи соответствует определенное отношение.

Друзья

Дети одних
родителей
46 Глава 2 • Графы и отношения

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

Имя связи. Каждая связь имеет уникальное имя. Существует несколько спо­
собов обозначить связи. Мы будем часто использовать числа в качестве имен уз­
лов, поэтому для имен связей мы будем применять строчные буквы. Другой спо­
соб дать имя связи — использовать имена соединяемых узлов. Например, связь
между узлами 17 и 34 мы назовем (17, 34). Это правило не годится для графов с
несколькими связями между двумя узлами. Нам не обязательно всегда указывать
имя связи, в таких случаях мы его просто опускаем. Ни свойства графа, ни свой­
ства объектов и отношений, которые этот граф представляет, не зависят от того,
как мы назовем связи.

Вес связи. Связи могут обладать свойствами. Такие свойства называются ве­
сом связи. Простейшим возможным весом связи является факт ее существования.
Примером веса связи может служить отношение или все отношения между двумя
объектами. Если узлы обозначают шаги обработки, а связи показывают последо­
вательность этих шагов, то весом связи может быть: время выполнения програм­
мы по данному пути, вероятность выполнения именно этого пути (этой последо­
вательности), тот факт, что будет вызван определенный объект данных. Свойства
модели, изображаемой графом, напрямую зависят от веса связей. Задача тестиро­
вания —убедиться, что связи с весом имеют ожидаемый вес.

Направленная связь. Направленная связь изображается стрелкой. Направлен­


ные связи используются для обозначения несимметричных отношений: отноше­
ний, существующих лишь в заданном направлении. Примеры несимметричных
отношений: А отец Б, за А следует Б, Б использует А, А вызывает Б. Большинство
отношений в тестировании являются несимметричными, то есть в большинстве
тестовых моделей используются направленные связи. Если R — несимметричное
отношение, и A R Б, из этого не следует Б R А. Задача тестирования —убедиться,
что все направленные связи имеют заданные направления.
2.2. Основные термины 47

Ненаправленная связь. Связь, соответствующая симметричному отношению,


то есть двустороннему отношению. Строго говоря, ft — симметричное отноше­
ние, если из факта A ft Б следует (в соответствии с природой отношения) Б ft А.
Симметричные отношения изображаются двусторонними стрелками, поэтому
мы обычно опускаем стрелки на концах линий. В первом примере на рисунке две
противоположно направленные стрелки могут быть заменены или двусторон­
ней стрелкой или простой линией, поскольку отношение «дети одних родителей»
симметрично. В третьем примере, напротив, несмотря на то, что существуют от­
ношения в обоих направлениях, они различны и несимметричны. Симметричные
отношения довольно редко встречаются в тестировании, вот несколько приме­
ров таких отношений: А и Б родственники, А и Б женаты, А и Б соседи по комна­
те. Задача тестирования —убедиться, что все симметричные отношения на самом
деле симметричны.
Дети одних
родителей
Пол (Алия)
Дети одних
родителей

Дети одних
родителей
Пол г*~ ►(Алия)

Брат

Сестра

Граф. Граф —это набор узлов, имен узлов, весов узлов, связей, имен связей, ве­
сов связей и отношений между узлами. Если между двумя узлами существует от­
ношение, то между ними есть связь.
ВОПРОС: Что вы делаете, когда вам встречается граф?
ОТВЕТ: Исследую его!
Направленный граф. Граф, в котором все связи направлены. Большинство гра­
фов в тестировании — направленные. Задача тестирования — убедиться, что на­
правления связей совпадают с заданными.
48 Глава 2 • Графы и отношения

Ненаправленный граф. Граф, в котором все связи ненаправленные. То есть ни


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

Входящая связь. Связь, входящая в узел. В этом случае стрелка указывает на


узел.

Входной узел. Узел без входящих связей. Хотя у программы обычно есть вход­
ные точки (например, BEGIN), графы, моделирующие поведение программ, могут
и не иметь входных узлов.

Исходящая связь. Связь, выходящая из узла. В этом случае стрелка начинается


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

Узел ветвления. Узел с двумя или более исходящими связями. В языках про­
граммирования примерами узлов ветвления служат операторы CASE или IF-THEN-
ELSE. На рисунке узел имеет три ветви. Обратите внимание, что это узел ветвления
в графе, моделирующем поведение программы, в самой же программе соответ­
ствующего ветвления может и не быть.
2.2. Основные термины 49

Выходной узел. Узел без исходящих связей. На рисунках изображены выход­


ные узлы, поскольку ни одна стрелка на них не начинается. Хотя у программы
обычно есть выходные точки (например, END), графы, моделирующие поведение
программ, могут и не иметь выходных узлов.

Путь. Поставьте карандаш на какой-либо узел на рисунке (например, на 14)


и следуйте по стрелкам до другого узла (например, узла 17); это и есть путь от узла
14 к узлу 17. Однако если вы можете прочертить путь на графе, это не значит, что
ваша программа может повторить этот путь. Путь в этом контексте не обязательно
является путем в коде программы. В поведенческом тестировании мы рассматри­
ваем пути в моделях, описывающих поведение программного обеспечения. Такие
пути могут соответствовать путям в программе, а могут и не соответствовать им.

Проходимый путь. Путь в модели, для которого существует такой набор вход­
ных значений, что, используя их, программа может пройти по этому пути.
Непроходимый путь. Путь в модели, который невозможно воспроизвести в
программе, какой бы набор входных значений мы ни взяли.
Путь вход—выход. Путь от входного узла к выходному узлу. Если отдельно не
оговаривается, под термином «путь» подразумевается «путь вход—выход».
Сегмент пути. Обычно путь, не являющийся путем вход—выход.
Имя пути. Существует два способа назвать путь: по именам узлов вдоль это­
го пути или по именам связей вдоль пути. Если мы назовем путь на следующем
рисунке по именам узлов, то получим: «14,99,12,17», если по именам связей, то
«кгт».
50 Глава 2 • Графы и отношения

Длина пути. Существует два способа измерить длину пути. Можно восполь­
зоваться числом узлов вдоль этого пути или количеством связей вдоль пути.
В данной книге мы, как правило, будем считать связи. Предыдущий рассмотрен­
ный путь был длиной в три связи или четыре узла.
Цикл. Путь, в котором как минимум один узел встречается больше одного раза.
Иначе говоря, это путь, в имени которого больше одного раза встречается имя
узла (связи), в зависимости от того, как строится имя пути — перечислением уз­
лов или перечислением связей. В примере на рисунке существует циклический
путь 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.
52 Глава 2 • Графы и отношения

2.3.5. Модель времени выполнения


Объекты. Линейные последовательности операторов в программе.
Отношение «предшествует оператору». Например, READ filename предшествует
оператору FOR....
Связи. Соединяют следующие друг за другом операторы. Соответствуют отно­
шению «предшествует между двумя узлами». Обратите внимание, что операторы
ветвления (такие как IF, CASE) имеют по одной исходящей связи на каждую ветвь.
Свойства.
1. Связей —ожидаемое время выполнения (например, в микросекундах);
2. Операторов ветвления (например, IF...THEN...ELSE, CASE) —вероятности события
для каждой их ветви (исходящей связи), что программа пойдет именно по
ней.

2.4. Отношения
2.4.1. Обзор
Отношения имеют определенные свойства и, следовательно, могут быть раз­
биты на категории. Если, глядя на отношение, вы говорите: «О, это такой-то и
такой-то тип отношений», то эти ваши знания вы сможете применить в конк­
ретных случаях. Мы не будем рассматривать все свойства всех возможных от­
ношений. Остановимся лишь на отношениях, наиболее часто используемых при
тестировании.

2.4.2. Транзитивные и нетранзитивные отношения


Отношение Й транзитивпо, если из А Й Б и Б Й В следует АЙВ. Например, от­
ношение быстрее — транзитивно. Если А быстрее Б и Б быстрее В, то, следова­
тельно, А быстрее В. Примеры транзитивных отношений: можно достичь, больше,
меньше, больше или равно, меньше или равно, зависит от, подмножество, находит­
ся в проекции.

Отношение, не являющееся транзитивным, — нетранзитивно. Примеры не­


транзитивных отношений: друг, сосед, лжет, связан (напрямую). К примеру, из
факта, что А лжет Б, а Б лжет В не следует, что А лжет В. В принципе А мог сол­
гать В, но это никак не следует из того, что А лгал Б, а Б лгал В. Например, мы зна­
ем, что А вообще не разговаривал с В.
Хотя в большинстве случаев легко можно понять, являются отношения тран­
зитивными или нет, в общем случае это не всегда так. Примером игры, построен­
ной на транзитивности, может служить детская игра «Камень, ножницы, бумага»
В этой игре ножницы режут бумагу, бумага покрывает камень, а камень тупит
2.4. Отношения 53

ножницы. Дело усложняется тем, что все три отношения {режет, покрывает, ту­
пит) эквивалентны в данном случае отношению сильнее, чем. На неоднозначности
транзитивности построено также много других детских и взрослых игр.
В наших интересах (поскольку это одна из задач тестирования) проверить, что
все отношения, которые должны быть транзитивны, действительно транзитивны,
и наоборот, если транзитивность не является свойством отношения, то необходи­
мо проверить, что оно нетранзитивно. В естественных языках это бывает не всегда
очевидно, поэтому спецификации могут вводить в заблуждение. Например, час­
то встречающееся отношение связан в естественном языке может интерпретиро­
ваться неоднозначно. Значит ли это, что из узла А можно достичь узла Б, или это
значит, что А напрямую связан с Б? В первом случае отношение можно достичь
должно быть транзитивно. Это значит, что если из А можно достичь Б, а из Ъ мож­
но достичь В, то из А можно достичь В. Но отношение можно достичь не обяза­
тельно транзитивно. Что, если мы добавим «прикоснувшись к руке»? Например,
я могу достичь своей соседки, прикоснувшись к ее руке, а она, в свою очередь, мо­
жет достичь своей соседки, прикоснувшись к ее руке, однако это не значит, что я
могу достичь ее соседки, прикоснувшись к ее руке, если я, конечно, не орангутан
или если мы не сидим очень близко.
Всегда обращайте внимание и проверяйте транзитивность или нетранзитив-
ность всех отношений из спецификации. Кроме этого, проверяйте программиста
на его понимание транзитивности или нетранзитивности. Если понятие транзи­
тивность неоднозначно трактуется в спецификации или программистом, то у вас
плодородная почва для тестирования.

2.4.3. Симметричные и несимметричные отношения


Отношение называется симметричным, если оно справедливо как в одну, так и
в другую сторону. Это означает, что стрелка на графе направлена в обе стороны.
Примеры: сосед, находится в браке. Отношение сосед симметрично, но не тран­
зитивно.
В английском языке для симметричных отношениях обычно используют обо­
рот «А и Б находятся в отношении», вместо «А относится к Б». То есть мы гово­
рим: А и Б находятся в браке, А и Б соседи и так далее.
Отношение, не являющееся симметричным, называется несимметричным. То,
что отношение не симметрично, еще не означает, что связь между парой узлов
должна быть односторонней, это говорит лишь о том, что существование связи в
обоих направлениях —не обязательное условие.
Симметрия — это очень важное свойство отношений, и нам следует тестиро­
вать отношения на симметричность. Например, если вы тестируете меню в про­
дукте, управляемом через меню (то есть в продукте, работа с которым происходит
посредством выбора определенных пунктов в меню), то, проверяя симметричность,
вы фактически проверяете, всегда ли существует возможность возврата в преды­
дущее меню. Аналогично если в программе (в текстовом редакторе, или, скажем,
электронной таблице) есть функция UNDO, это значит, что большинство операций
симметричны, поскольку всегда можно отменить действия оператора. Однако даже
54 Глава 2 • Графы и отношения

идеальное UNDO не может быть полностью симметричным, поскольку существуют


такие операции, как печать или отправить (PRINT, SEND), которые нельзя отменить.
С симметричностью, как и с транзитивностью, часто возникает путаница в спе­
цификациях, или по вине программистов. Естественные языки, как водится, тоже
усложняют нам жизнь, однако в случае симметричности проблемы возникают,
поскольку (в большей йли меньшей степени) в них симметричность подразумева­
ется, а не постулируется явно.
Всегда обращайте внимание и проверяйте симметричность или несимметрич­
ность всех отношений из спецификации. Кроме того, проверяйте программиста на
его понимание симметричности или несимметричности. Если понятие «симмет­
ричность» неоднозначно трактуется в спецификации или программистом, то у вас
появится плодородная почва для тестирования.

2.4.4. Рефлексивные и нерефлексивные отношения


Отношение называется рефлексивным, если каждый узел находится в этом отно­
шении с самим собой. Это означает, что каждый узел имеет связь, ведущую обрат­
но на него (петля). Примеры рефлексивных отношений: знаком с (поскольку, если
у меня нет амнезии, я знаком сам с собой), родственник, может коснуться, связан
с, равен, эквивалентен.

Если рефлексивность не выполняется для каждого узла в диаграмме, то отно­


шение называется нерефлексивным. Следующие отношения нерефлексивные:
друг (как часто можно услышать: «Он сам себе злейший враг»), выше, ниже.
Рефлексивность — это возможность остаться в исходном состоянии. Ре­
флексивность является важным свойством наших моделей (если она есть). Я как-
то работал с неудачным текстовым редактором, в котором необходимо было что-
то выбирать в каждом меню. Это можно было сделать, используя мышь (которой
у меня в то время не было) или вводя ключевую букву, соответствующую первой
букве в названии пункта меню. В таких случаях, если я ввожу неправильную бук­
ву, я должен остаться в том же самом меню, но самонадеянная программа вмес­
то этого делала выбор за меня и, как правило, неверный. Используемые меню не
были рефлексивными в этом странном продукте.
2.4. Отношения 55

Рефлексивность также чаще подразумевается, чем постулируется, и, следова­


тельно, является хорошим объектом для поиска ошибок. Поскольку рефлексив­
ность должна быть присуща каждому узлу, каждый узел должен быть проверен.
Тестируйте рефлексивность по тому же принципу, что и транзитивность с сим­
метричностью.

2.4.5. Классы эквивалентности и разбиения


Отношение эквивалентности — симметрично, транзитивно и рефлексивно. Набор
объектов, удовлетворяющих отношению эквивалентности, называется классом
эквивалентности. Каждый объект из этого класса называется эквивалентным
(в смысле данного отношения) любому другому объекту этого класса.
Все методы, описываемые в этой книге, являются примерами тестирования пу­
тем разбиения [HAML88, 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 или оставьте
эту позицию пустой или же отметьте ее точкой.
56 Глава 2 • Графы и отношения

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

17 34

17 . 1

34 .

На следующем рисунке представлен граф, описанный в пункте 2.2.

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, будет представлен в следующем виде:
2.5. Основополагающие принципы тестирования 57

7: 14(a) 12: 17( т ) . 16(у)


14: 99(Ю . 13(0 17: 7(b)
13: I 2 ( z ) . 17(c) 16: 99 (q ). 43(h)
99: 12(г) 43: 1 2 ( х ) . 7(w)

Вы можете изменять этот порядок записи по своему усмотрению, добавлять


свойства, комментарии или что-то еще, чтобы список был понятным для вас и од­
нозначно определял:
1. Начальный узел связи.
2. Конечный узел связи.
3. Все свойства связи.
4. Все свойства узла.
Для больших графов удобно записывать каждую связь на отдельной стро­
ке, оставляя место для комментариев и других аннотаций, относящихся к связям.
Также может быть удобно записывать пояснения или ссылки на соответствующие
параграфы так, как это сделал я:
7: 14(a) {перезапуск процесса: см. раздел 3 . 1 . 4 . 1 . 5 . 9 }
14:9 9 ( к ) {загрузка точки входа: см. раздел 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. Разработайте тесты для циклов.
ВОПРОС: Что вы делаете, когда вам встречается граф?
ОТВЕТ: Исследую его!
58 Глава 2 • Графы и отношения

2.5.2. Построение графа


1. Определение узлов.
• Какие объекты (узлы) представлены на данном графе? Каждому рас­
сматриваемому объекту соответствует один узел.
• Дайте имена узлам. Вы называете узлы по своему усмотрению, однако
каждый узел должен иметь уникальное имя или идентификатор. Мне
нравится использовать числа, но вы, возможно, отдадите предпочтение
именам, несущим определенный смысл в контексте вашего приложе­
ния.
• Узлы могут обладать также свойствами (весами). Отметьте свойства
(значения) для каждого узла.
2. Определение связей.
• Каждая связь должна начинаться и заканчиваться на узле (это может
быть один и тот же узел). Поскольку довольно часто предполагается на­
личие входного и/или выходного узла, вам, возможно, придется доба­
вить их в вашу модель. Если связь оборвана (то есть приходит ниоткуда
или ведет в никуда), то в построении модели допущена ошибка.
• Дайте имена связям. Если между парой узлов существует больше одной
связи, то разумно дать каждой связи свое уникальное имя. Если два узла
может соединять только одна связь, то давать ей имя не обязательно.
• Отметьте веса каждой связи.
3. Найдите входной и выходной узлы. В графе модели не обязательно при­
сутствуют входной и выходной узлы, но часто есть оба. Если в графе все-
таки есть входной и/или выходной узлы, то, по всей видимости, они игра­
ют важную роль. Обозначьте все входные и выходные узлы соответственно.
Например: 14 (ВХОД):... или 44 (ВЫХОД). Помните, что у входных узлов
нет входящих связей, а у выходных нет исходящих связей.
4. Найдите все циклы. В графах моделей не обязательно присутствуют циклы,
но если они есть, то они важны. Мы будем использовать специальные мето­
ды тестирования циклов, поэтому вам надо будет найти все циклы на диа­
грамме. Существуют способы сделать это автоматически (то есть алгорит­
мически), но они не описываются в этой книге, см. [BEIZ90].

2.5.3. Определение отношений


1. Начните с написания отношений на английском языке (или на вашем род­
ном языке).
2. Ответьте ДА или НЕТ на следующие вопросы:
• Оно рефлексивно?
2.5. Основополагающие принципы тестирования 59

• Оно симметрично?
• Оно транзитивно?
Если оно рефлексивно, то каждый узел должен иметь петлю. Если оно симмет­
рично, то каждая связь должна быть двусторонней. Отношения на графе не обяза­
тельно должны обладать этими свойствами. Более того, они могут обладать други­
ми свойствами, не рассматриваемыми в этой книге (см. [BEIZ90], глава 12). Какими
бы ни были свойства отношений, они должны проверяться при тестировании.

2.5.4. Проверка узлов


Меньшее из всего, что вы можете сделать, —это провести достаточно тестов, для того
чтобы убедиться, что все узлы именно такие, какими и должны быть. Такие тесты на­
зываются проверкой узлов. У проверки узлов, однако, есть своя градация по степени
совершенства тестов. Ниже приводится список тестов (в порядке возрастания при­
оритета), которые надо провести, чтобы полностью выполнить проверку узлов.
1. Тесты, чтобы убедиться в наличии всех заданных узлов. Ни один узел не
должен быть пропущен.
2. Тесты, чтобы убедиться в отсутствии лишних узлов (это может потребовать
неограниченного числа тестов и поэтому быть неосуществимо).
3. Тесты, чтобы убедиться в корректности весов узлов, если они есть.
4. Если существуют входной и выходной узлы, то в завершение предыдущих
шагов можно выбрать пути от входа до выхода и выбрать входные значения
так, чтобы программа проследовала по каждому из заданных в модели пу­
тей. Обычно задают несколько таких путей от входа к выходу (тестовых ва­
риантов).
Как уже говорилось, проверка узлов —это очень слабые тесты, на практике они
оказываются настолько слабы, что фактически не используются. Все методы, из­
лагаемые в этой книге, предполагают, что вы по меньшей мере выполнили провер­
ку связей (см. ниже). Проверка связей, в свою очередь, подразумевает, что выпол­
нены все тесты проверки узлов.

2.5.5. Проверка связей


Следующее по эффективности действие, которое можно сделать, —это провести
достаточно тестов, для того чтобы убедиться, что все связи именно такие, каки­
ми и должны быть. Такие тесты называются проверкой связей. Ниже приводится
список тестов (в порядке возрастания приоритета), которые надо провести, чтобы
полностью выполнить проверку связей.
1. Тесты, чтобы убедиться в наличии всех заданных связей, — что ни одна
связь не пропущена.
2. Тесты, чтобы убедиться в отсутствии лишних связей (Это может потребо­
вать неограниченного числа тестов и поэтому быть неосуществимо).
60 Глава 2 • Графы и отношения

3. Тестирование отношений.
• Если отношение симметрично, то необходимо убедиться, что каждая
связь является двусторонней: например, D0/UND0.
• Если отношение рефлексивно, то необходимо убедиться, что каждый
узел связан сам с собой: например, DO NOTHING.
• Если отношение транзитивно, то вы должны проверить его транзитив­
ность в любой ситуации. Это делается следующим образом. Рассмотрим
три объекта, А, Б и В, причем А связано с Б, а Б связано с В. То есть А Й Б
и Б Й В. Показав (путем тестирования), что А Й Б —истина и Б Й В —ис­
тина, необходимо показать, что А Й В тоже является истиной. Сделайте
это для каждой тройки узлов, в которой выполняются данные условия.
4. Если существуют входной и выходной узлы, то шаги 1-3, как правило, за­
вершаются подбором путей от входа к выходу, при этом выбираются такие
входные параметры, с которыми программа проследует по выбранным путям.
Чаще всего для теста указывают несколько путей ВХОД/ВЫХОД (тестовых
вариантов). Заметим, что если вы осуществляете проверку связей, вы обычно
осуществляете и проверку узлов. Тем не менее, проверка связей в большин­
стве случаев требует большего количества тестов, чем проверка узлов.
При тестировании черного ящика, исключая патологические случаи, если вы
разрабатываете тесты проверки связей, вы вместе с тем добиваетесь и проверки
узлов. Однако вы вряд ли сможете убедиться, что не существует лишних узлов и
что веса узлов, если узлы обладают весами, верны. Хорошей идеей будет добавле­
ние в проверочный список инспектирования тестов и в ваш проект тестов требо­
вания проверки узлов из раздела 2.5.4.

2.5.6. Тестирование весов


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

2.5.7. Тестирование циклов


Мы уделяем специальное внимание тестированию циклов, так как статистика
ошибок показывает, что у программистов возникают проблемы с циклами. По
этой причине циклам посвящена целая глава (см. главу 4). В этом разделе излага­
ются лишь основы.
В нашу задачу не входит анализ кода чтобы увидеть, есть в нем циклы или
нет. Мы проводим тестирование циклов, если наша модель поведения программы
включает в себя циклы.
Цикл — это последовательность имен узлов, в которой как минимум одно имя
узла повторяется. Если появляется другая последовательность повторяющихся
имен узлов или она просто возможна, то у вас есть еще один цикл. Вы должны
протестировать каждый цикл.
2.6. Резюме 61

Тестирование цикла основано на том, сколько раз вы будете выполнять этот


цикл. Вы можете совсем обойти цикл, можете пройти его один раз, два раза....
Максимальное количество проходов обозначим как п. В следующем примере есть
узел, который является входом в цикл (А) и два узла, которые являются выход­
ными в цикле (X и Y).

1. Обойдем цикл: АХЕ или AXYZE. (Я буду использовать оба пути.)


2. Пройдем цикл один раз: AXYVWXEили AXYVWXYZE.
3. Пройдем цикл два раза: AXYVWXYVWXE или axywxyvwxyze.
4. Пройдем цикл обычное число раз: A(XYVW)typica1XE.
5. Пройдем цикл максимальное число раз (n): A(XYVW)nXE и A(XYVW)nXYZE.
6. Пройдем цикл п-1 раз: A(XYVW)nхХЕ и A(XYVW)nxXYZE.
7. Попытаемся пройти цикл n + 1 раз: A(XYVW)"*xXE и A(XYVW)ntlXYZE.
Рассмотрим два каких-нибудь узла в модели, скажем, А и В. Если существует
путь от А к В (не обязательно прямая связь) и другой путь от В к А, и это верно для
каждого А и В, то существует возможность, стартуя от любого узла, по какому-то
пути прийти к любому другому узлу и вернуться назад к начальному узлу. Такие
графы называются сильно связанными. Исчерпывающее тестирование цикла, как
было определено, обычно является излишней тратой времени в сильно связанных
графах. Очевидно, что граф с симметричными отношениями (или ненаправлен­
ный граф) является сильно связанным, так как все стрелки направлены в обе сто­
роны. Следовательно, тестирование циклов не является эффективным для графов
с симметричными отношениями.

2.6. Резюме
Вы освоили словарь и основную идею поведенческого тестирования. Может
быть, материал был изложен более кратко, чем вы бы хотели. Как я уже говорил в
README.DOC, эта глава — как подпрограмма, которую вы будете использовать
в последующих главах при создании конкретных тестов. Рассматривайте эту гла­
ву как объект в объектно-ориентированных программах, которые вы будете со-
.давать в последующих главах. ООП, на мой взгляд, более абстрактно, нежели эта
глава. Или же рассматривайте эту главу как игру, в которой вы должны победить.
Используйте следующие вопросы для оценки того, что вы вынесли из этой главы.
62 Глава 2 • Графы и отношения

2.7. Вопросы для самопроверки


1. Дайте определение: проходимый путь, несимметричное отношение, двоичное
отношение, узел ветвления, оператор ветвления, дерево вызова, комментарий,
граф потока управления, проверка (покрытие), оборванная связь, граф потока
данных, направленный граф, направленная связь, входной узел, путь вход—вы­
ход, класс эквивалентности, отношение эквивалентности, выходной узел, граф,
матрица графа, входящая связь, нетранзитивное отношение, перефлексив-
ное отношение, связь, проверка связей, представление списка связей, имя свя­
зи, вес связи, цикл, нециклический путь, программа, управляемая через меню,
узел, проверка узлов, имя узла, вес узла, исходящая связь, параллельные связи,
стратегия тестирования путем разбиения, путь, длина пути, имя пути, сегмент
пути, рефлексивное отношение, отношение, петля, соединять, сильно связан­
ный граф, симметричные отношения, граф потока транзакций, транзитивные
отношения, непроходимый путь, ненаправленный граф, ненаправленная связь.
2. Отношения могут быть: симметричными или несимметричными, рефлексив­
ными или нерефлексивными, транзитивными или нетранзитивными. Всего
насчитывается восемь различных комбинаций. В табл 2.1. приведены примеры
каждого типа отношений. Придумайте еще по три примера для каждого типа.
Докажите принадлежность каждого к тому или иному типу (то есть протести­
руйте их). Подсказка: попробуйте использовать Тезаурус Роже.345
Таблица 2.1. Примеры отношений
Симметричное Рефлексивное Транзитивное Примеры
нет нет нет любит, грубит, спорит,
критикует, владеет
нет нет да выше, длиннее
нет да нет знаком с
нет да да больше или равен
да нет нет двоюродные сестры,
женаты, обручены
да нет да параллелен, сосед
да да нет рядом с
да да да равен

3. Определите, является ли отношение «находится в проекции» транзитив­


ным? Придумайте ситуацию или способ освещения, при котором данное
отношение нетранзитивно.
4. Рассмотрите отношение был объединен с с точки зрения его симметричнос­
ти, рефлексивности, транзитивности. Приведите примеры и контрпримеры,
подтверждающие ваши выводы.
5. Исследуйте следующие отношения (на предмет их симметричности, реф­
лексивности, транзитивности) и подтвердите свои выводы, продемонстри­
ровав отсутствие контрпримеров: А вызывает Б, А не равно Б, А согласен с Б,
А эквивалентен Б, А согласуется с Б, А совместим с Б, А несовместим с Б, А —
часть Б, А —вне Б, к лучше, чем Б, А доминирует над Б, А зависит от Б.
Тестирование
потока управления

3.1. Обзор
В этой главе в качестве основной модели, используемой при разработке тестов,
рассматривается граф потока управления1. С помощью графа потока управления
мы будем моделировать различные части формы 1040 декларации о доходах внут­
ренней налоговой службы США (форма 1040 ВНС), сложность тестирования ко­
торой сравнима с ее собственной сложностью. В дальнейшем модель будет ис­
пользована для построения набора тестов по проверке связей.

3.2. Основные термины


Внешние термины: алгебра, алгебраический, И (логическое), приложение,
язык ассемблера, логическая ветвь, ошибка, оператор CASE, COBOL, код, завер­
шать, сложность, вычисление, последовательный, ограничение, противоречие,
управление, поток управления, копировать, программа для решения уравнений,
ИСКЛЮЧАЮЩЕЕ ИЛИ (логическое), выполнять, выражение, крайние значе­
ния, формальная модель, оператор IF, оператор IF-THEN-ELSE, оператор, ЛОЖЬ,
оператор GOTO, реализация, ВКЛЮЧАЮЩЕЕ ИЛИ (логическое), приращение,
неравенство, экземпляр, прыжок, логика, логическое выражение, логическое
значение, L O TU S-123, сопровождение, матрица, пропущенные требования, мо­
дель, ошибка модели, моделирование, имя, естественный язык, вложенный, НЕ

1 Поток управления задает последовательность действий при выполнении программы, он соот­


ветствует цепочке операторов программы, последовательно передающих друг другу управление ком­
пьютером. — Примем, иаучн.ред.
64 Глава 3 • Тестирование потока управления

(логическое), численный, оператор, ИЛИ (логическое), вставка, обработка, шаг


обработки, программа, программист, программирование, псевдокод, реализм,
перепрофилирование, выпуск, требования, перезапись, коммерческая презен­
тация, предложение, система уравнений, программное обеспечение, специфика­
ция, ошибка спецификации, электронная таблица, структурированная програм­
ма, символическая подстановка, таблица, ошибка теста, проектирование теста,
тестировщик, дерево, ИСТИНА, таблица истинности, значение истинности,
неструктурированное программное обеспечение, значение, версия, текстовый
редактор.
Внутренние термины: проходимый путь, поведение, поведенческое тестирова­
ние, тестирование черного ящика, слеп, покрытие ветви, ошибка, случайная кор­
ректность, контроль конфигурации, покрываемые пути, входной узел, выходной
узел, характеристика, граф, модель на основе графа, входящая связь, ввод, вход­
ное значение, связь, покрытие связей, вес связи, представление графа в виде спис­
ка связей, цикл, недостающая характеристика, недостающий путь, узел, имя узла,
объект, оракул, итог, вывод, исходящая связь, параллельные связи, путь, сегмент
пути, прототип, отношение, требование, спецификация, отрезок пути, тестовый
вариант, тестовый комплект, метод тестирования, инструмент тестирования, не­
проходимый путь, тестирование модуля, критерий соответствия.
Логический предикат. Предложение или выражение, которое может прини­
мать логическое значение ИСТИНА или ЛОЖЬ. Примеры: «Небо голубое», «Это
утверждение ЛОЖНО», «Ваш родитель может предъявлять на вас права, пос­
кольку вы зависите от его доходов», «Утверждается, что ваш ребенок, находится
на вашем иждивении в соответствии с соглашением, принятым до 1985 года».
Предикат выбора. Выражение, которое может принимать более двух значений
и служит для выбора одного из нескольких вариантов. Пример: «Отметьте только
одну позицию — (1) холост, (2) женат, заполняю совместную налоговую деклара­
цию, (3) женат, заполняем раздельные налоговые декларации, (4) глава хозяйства,
(5) вдовец». Термин «предикат» часто используется для обозначения как логиче­
ских предикатов, так и предикатов выбора.
Логическое И. В логических и формальных моделях «И» строго определяет­
ся, следующим образом: А & Б будет истиной в том и только в том случае, если
оба, А и Б, истинны. Однако в нестрого логических и неформальных докумен­
тах, таких как бланки декларации на подоходный налог, слова и фразы, подоб­
ные «еще», «также», «в дополнение к» и даже «или» могут на самом деле озна­
чать логическое И.
Логическое ИЛИ. В логических и формальных моделях «ИЛИ» всегда означает
ВКЛЮЧАЮЩЕЕ ИЛИ, иначе «И/ИЛИ». Неформальное использование может
быть различным и при интерпретации рекомендуется быть осторожным.
Логическое НЕ. В логических и формальных моделях вам следует заключить
предложение в скобки и поставить оператор НЕ впереди, как, например, «НЕ
(ваш ребенок живет с вами)» вместо «ваш ребенок НЕ живет с вами». При нефор­
мальном написании НЕ может стоять практически в любом месте в предложении,
поэтому надо быть внимательным.
3.3. Отношения и модель 65

Составной предикат. Логическое выражение, включающее два или более пре­


дикатов, связанных операторами И, ИЛИ или НЕ. Примеры: (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, s a l a r i e s , t i p s (оклады, дополнительные доходы, чаевые).
8а. (введите) t a x a b le i n t e r e s t income (налогооблагаемый доход).
8Ь. (введите) tax-exempt i n t e r e s t income (не облагаемый налогом доход).
9. (введите) d iv id e n d income (доход по дивидендам).
10. (введите) t a x a b le refunds, c r e d i t s , or o f f s e t s o f s t a t e and l o c a l income
taxes (налогооблагаемые платежи, кредиты, компенсации местного
подоходного налога и подоходного налога в казну штата). * 3

' Я не выдумал это сам. Данная спецификация — это путь выполнения в форме SE ВНС, 1994.
Можете убедиться сами. Подоходный налог 101 — определенно более напряженный курс, нежели про­
граммирование 101 или тестирование 101.

3 Зак. 770
66 Глава 3 • Тестирование потока управления

11. (введите) alimony re ceiv e d (полученные алименты).


12. (введите) busin ess income or lo s s (доход или убыток от предпринимательской
деятельности).
13. (введите) c a p i t a l ga in or lo s s (капитальные прибыль или убыток).
14. (введите) o th e r ga in s or lo s s e s (другие прибыли или убытки).

Ниже приведены некоторые из возможных моделей графов для данной специ­


фикации.

7-14

Отношения (связи): за ... непосредственно следует ... Если в предыдущем при­


мере использовать один узел для каждого шага, то за узлом 9 непосредственно сле­
дует узел 10, а за узлом 10 непосредственно следует узел 11, и так далее.
Узел с предикатом. Узел с двумя или более исходящими связями, вес каждой
из которых равен значению предиката. То есть ИСТИНА/ЛОЖЬ для логическо­
го предиката и по одному из нескольких вариантов для предиката выбора. Узел с
предикатом выбирает один из двух или более альтернативных путей, по которым
может пойти процесс.
Пример: Строки с ЗЗЬ по 34 в форме 1040.
ЗЗЬ. Если ваши родители могут утверждать, что вы находитесь на их иждивении, отметьте
графу ЗЗЬ. в противном случае не отмечайте графу ЗЗЬ.Граф, моделирующий это предложение,
изображен на рисунке.

«ваши родители могут узел в модели


утверждать, что вы находитесь
на их иждивении?»

Узел выбора. Узел с двумя или более исходящими связями, вес каждой из ко­
торых равен одному из значений величины выбора.
Пример: строка 34 в форме 1040: Введите наибольшую из ваших льгот, перечис­
ленных в бланке А, строка 29 ИЛИ обычная льгота для вашей формы заполнения, ука­
3.3. Отношения и модель 67

занная ниже. Однако, если вы отметили какую-либо графу на строке 33а или Ь. сле­
дуйте инструкциям для определения ваших стандартных льгот. Если вы отметили графу
33с, ваша стандартная льгота равна нулю, (а) холост = $3,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а или ЗЗЬ? 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 были соединительными узлами.
68 Глава 3 • Тестирование потока управления

Некоторые комментарии, касающиеся данной модели.


1. Узел 34 — узел с предикатом. Обратите внимание на использование здесь
союза «или». Это не логическое ИЛИ. Это способ обозначить предикат1.
2. Предикат для узла 34.2 является составным предикатом, и ИЛИ здесь име­
ет смысл включающего ИЛИ, поскольку можно отметить как одну графу,
так и обе одновременно. Формальная запись данного предиката будет сле­
дующей: «Вы отметили графу 33а ИЛИ вы отметили графу ЗЗЬ (или обе)».
Этот предикат также представляет интерес из-за использования в нем слова
«однако». Ключевым словом в этом случае является не «однако», а следую­
щее за ним «если».
Вот более подробная модель для этого узла:
34.2 Отмечена графа 33а? 34.3 ИСТИНА
34 .2 .1 ЛОЖЬ
34 .2 .1 Отмечена графа ЗЗЬ? 34.3 ИСТИНА
34.4 ЛОЖЬ

А вот еще более подробная модель для этого узла:


34.2 Отмечена графа 33а? 34 .2 .2 ИСТИНА
34 .2 .1 ЛОЖЬ
34 .2 .1 Отмечена графа ЗЗЬ? 34.3 ИСТИНА
34.4 ЛОЖЬ
34 .2 .2 Отмечена графа ЗЗЬ? 34.3 ЛОЖЬ

Эта модель лучше первоначальной, поскольку она вскрывает сложность


составного предиката и мы, скорее всего, обнаружим больше ошибок с
ее помощью [MYER79]. Первая улучшенная модель может быть слепа к
определенному типу ошибок, так как в ней не хватает критического подхода
к предикату в узле 34.2. Вторая модель более сбалансирована, и в ней
делается меньше предположений о способе реализации. Поэтому, хотя она
и более сложная, она лучше ищет ошибки, и я выбираю ее.
3. Предикат в строке 33с является составным предикатом: «(Вы женаты, за­
полняете раздельные налоговые декларации И льготы вашей супруги де­
тализированы) ИЛИ вы иностранец с двойным гражданством». Здесь фи­
гурирует включающее ИЛИ, поскольку вы можете быть иностранцем с
двойным гражданством (что бы это ни значило) и ваша супруга может за­
полнять налоговую декларацию раздельно и ее льготы могут быть дета­
лизированы. Обратите внимание, что если вы не являетесь иностранцем с
двойным гражданством, то должны выполняться три условия: (1) вы жена­
ты, (2) вы заполняете налоговые декларации раздельно, (3) льготы вашей
супруги детализированы.
4. Один из альтернативных пунктов в узле 34.5 скрыт под союзом «или». Это
не логическое ИЛИ. Это способ обозначить параллельные связи и дополни­

1 На самом деле это не узел с предикатом, а нечто иное, что будет рассмотрено в главе 6 при из­
учении тестирования потока транзакций. Это не настоящий предикат, поскольку вы можете выбрать
оба альтернативных варианта.
3.3. Отношения и модель 69

тельные варианты выбора: «заполняю совместную налоговую декларацию»


и «вдовец».
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 Стандартные или 35 Детализированные/ GOTO Бл. А
Стр. 29
Детализированные льготы?
34.2 Стандартные
34.2 Отмечена графа 33аили ЗЗЬ? 35 ИСТИНА/GOTO СТР. 22
34.4 ЛОЖЬ
34.4 Отмечена графа 33с? 35 ИСТИНА/ Отч.= $0
34.5 ЛОЖЬ
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. Моделирование составных предикатов


Составные предикаты обманчивы, поскольку таят в себе подводные камни. Они так­
же перспективны в смысле тестирования, так как программисты часто делают в них
ошибки. Вы всегда можете подробно расписать составной предикат, для того чтобы
вскрыть его сущность и построить его модель при помощи графа или таблицы. Ниже
приводится модель на основе графа. Предположим, у вас есть составной предикат, со­
стоящий из нескольких простых предикатов (то есть не составных), которые мы будем
называть А, В, С. Например: «А&В ИЛИ С». Вы строите дерево предикатов с числом
70 Глава 3 • Тестирование потока управления

ветвей, равным числу возможных вариантов. Для двух предикатов, число ветвей бу­
дет равно четырем, для трех предикатов —будет восемь ветвей, для п простых преди­
катов —2"ветвей.

На рисунке показан первый шаг. Порядок, в котором вы рассматриваете пре­


дикаты, здесь не важен. Важно, чтобы все 2" ветвей (в нашем примере восемь)
были рассмотрены. Следующий шаг — собрать все исходящие связи для случая
ИСТИНА в узел со значением ИСТИНА, а все связи для случая ЛОЖЬ в узел со
значением ЛОЖЬ, как показано на следующем рисунке.

В итоге одиночный узел с составным предикатом «А&В ИЛИ С» заменяется


на более подробную модель, на которой показаны все части предиката. Вам мо­
жет показаться, что верхний узел с предикатом С избыточен, поскольку вне зави­
симости от его значения результат будет — ИСТИНА. Тем не менее, он здесь не
лишний, поскольку все эго будет так при условии отсутствия ошибок в реализа­
ции. Только путем тестирования всех восьми случаев (2й в общем случае) мы мо­
жем убедиться, что логика, вне зависимости от способов ее реализации, не содер­
жит ошибок. Вы можете отступиться и не тестировать точно все 2Пслучаев. Это
здорово, если не обращать внимания на то, что ваше тестирование становится сла­
бым и вы можете пропустить больше ошибок.
Другой способ построить модель— использовать таблицу истинности (см.
табл. 3.1) вместо дерева графа. Вы используете один узел для составного предика­
та, с условием что все варианты должны быть проверены по таблице истинности.
3.4. Методика 71

Таблица 3.1. Таблица истинности


А в с А&В ИЛИ С
ИСТИНА ИСТИНА ИСТИНА ИСТИНА
ИСТИНА ИСТИНА ложь ИСТИНА
ИСТИНА ложь ИСТИНА ИСТИНА
ИСТИНА ложь ложь ложь
ЛОЖ Ь ИСТИНА ИСТИНА ИСТИНА
ЛОЖ Ь ИСТИНА ложь ложь
ЛОЖЬ ложь ИСТИНА ИСТИНА
ложь ложь ложь ложь
Напоминаю, что в таблицу истинности записываются состояния простых пре­
дикатов, и просчитывается, какое из значений ЛОЖЬ или ИСТИНА будет иметь
составной предикат для данной комбинации. Я использую таблицы для про­
верки составных предикатов, состоящих более чем из трех простых предикатов.
Добавление в граф четырех узлов для составного предиката, состоящего из двух
элементов, не создаст в модели слишком большой путаницы. Однако уже трех­
компонентный предикат сильно загрузит модель, а добавление четырехкомпонен­
тного фактически нереально. Помните, что вы не можете не принимать в расчет
возможность существования ошибок в вашей модели.

3.4. Методика
3.4.1. Основы
Проектирование теста и его выполнение состоит из следующих шагов:
1. Изучите и проанализируйте требования на предмет их доступной для реа­
лизации завершенности и самосогласованности. Убедитесь в том, что спе­
цификация корректно отражает требования, внесите поправки в специфи­
кацию, если это не так.
2. Перепишите спецификацию в виде последовательности коротких предло­
жений. Уделите специальное внимание предикатам. Разделите сложные
предикаты на эквивалентные последовательности простых предикатов.
Найдите узлы выбора и выпишите их в виде простых списков. Удалите лю­
бые логические «И», которые не являются частью предикатов, вместо этого
разбейте предложение на две части.
3. Однозначно пронумеруйте предложения. Впоследствии это будут имена
узлов.
4. Постройте модель.
5. Проверьте модель —ваша работа так же подвержена ошибкам, как и работа
программиста.
6. Выберите пути тестирования.
72 Глава 3 • Тестирование потока управления

7. Активизируйте выбранные пути тестирования. То есть выберите такие


входные значения, используя которые программа, при условии отсутствия
ошибок, пройдет по пути, эквивалентному тому, который вы выбрали.
8. Предскажите и запишите вероятный итог каждого теста.
9. Определите критерий (критерии) соответствия для каждого теста.
10. Выполните тест.
11. Подтвердите итог.
12. Подтвердите путь.

3.4.2. Построение модели


Как пример для иллюстрации процесса мы будем использовать строчки с 32 по 40
формы 1040 ВНС. Исходная спецификация приведена в Приложении А. Проще все­
го мне будет это объяснить путем последовательного построения конкретной модели,
комментируя процесс по мере ее развития. Мои комментарии выделены курсивом.
Шаг 1: Проверить и обосновать требования. Вряд ли, что-то можно сделать,
поскольку мы рассчитываем, что ВНС делает это за нас.
Шаг 2: Переписать спецификацию. Что касается меня, я переписываю специ­
фикацию, используя мой собственный тип псевдокода. Использование полуфор­
мального языка (то есть псевдокода) помогает быть уверенным в однозначности
при описании вещей. Хотя это похоже на программирование, это не программиро­
вание —это моделирование.
Я использую представление в виде списка, так как это легче; хотя, когда я работал,
я рисовал маленькие графы для того, чтобы убедиться в корректности потоков дан­
ных для различных предикатов. Я включил мои некоторые наброски, чтобы помочь
вам увидеть, как я мыслил. Несмотря на то, что построение и использование целого
графа в виде рисунка чересчур громоздко, эти промежуточные наброски сегментов
маленького графа помогут вам получить правильное представление о логике.

65 или старше?

32: 33а1 введите adjusted_gross_income


(скорректированный_общий_доход)
33а1 33а2 положите счетчик_пометок равным нулю

Необходимо отслеживать число пометок, которые мы делаем в форме.


33а2 ЗЗаЗ если 65 или старше

Это узел с предикатом, то есть будет по крайней мере две исходящие связи.
33а4 если НЕ 65 или старше

Пропустить приращение, если менее 65.


3.4. Методика 73

ЗЗаЗ 33а4 приращение счетчика_пометок

Позднее нам будет необходимо знать общее число пометок, а этот способ моде­
лирования не хуже любого другого.
33а4 33а5 если слеп

Другой узел с предикатом.


ЗЗаб если не слеп

Пропустить приращение, если НЕ слеп.


33а5 ЗЗаб приращение счетчика_пометок

Увеличение числа пометок, если слеп.


ЗЗаб 33а7если супругу 65 или он старше

Заметим, что в действительности логика здесь намного сложнее. Если бы наша


модель была для всей формы 1040, то нам следовало бы учитывать корреляцию со
строчками 1-5, принимая во внимание способ заполнения декларации. Только об­
ладающие статусом (2) Женат или статусом (5) Вдова (вдовец) могли бы делать
отметки в этой и следующей графе. В реальной модели вы бы предварили этот и
следующий узел с предикатом другим узлом с предикатом, который спрашивает:
«Женат и заполняет совместную налоговую декларацию ИЛИ вдовец с детьми на
иждивении?» Если предикат является ИСТИНОЙ, вы выполняете узлы с ЗЗаб по
ЗЗаЭ, иначе вы переходите к узлу ЗЗаЮ. Однако для того чтобы сохранить при­
емлемый размер этой модели, мы не будем гнаться за реалистичностью и допус­
тим, что этот сегмент не зависит ни от каких предыдущих сегментов и логики.
Графическая реализация этой части модели приведена на рисунке.

33а8 если супругу НЕ 65 или больше


33а7 33а8 приращение счетчика_пометок
33а8 33а9 если супруг слеп
ЗЗаЮ если супруг НЕ слеп
33а9 ЗЗаЮ приращение счетчика_пометок

Узел ЗЗаЮ является излишним, так как мы изменяли счетчик пометок по мере
прохождения пути; однако я предпочитаю быть уверенным, что существует по
крайней мере один узел (для начала) для каждого утверждения в спецификации.
ЗЗЬЗ З Ы Если ваши родители могут предъявить на вас права

Узел с предикатом.
74 Глава 3 • Тестирование потока управления

33с Ваши родители не могут предъявить на вас права


ЗЗЬ1 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 — очень интересный случай. Он похож на предикатный узел, но на са­


мом деле это не так. Это пример того, что мы называем разбиением транзакции
(смотрите главу в.). Для того чтобы следовать инструкции (смотрите дальше
узел 34.13), то есть взять большую из детализированных ш и стандартных льгот,
вы должны выполнить оба вычисления, как для стандартной льготы, так и для де­
тализированной льготы. Фактически мы должны обрабатывать обе части парал­
3.4. Методика 75

лельно, иначе нечего будет сравнивать в узле 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

Эта модель тоже может быть выражена при помощи графа на следующем
рисунке.
Детализированные
льготы?
Бланк А

Помет,
графу ЗЗЬ?

Помет,
графу 33с?
76 Глава 3 • Тестирование потока управления

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 Строка_35 - строка_36
37.1 38 Больше нуля
37.2 Меньше или равен нулю
37.2 38 Введите ноль в строке 37
38 38.1 t a x t a b l e (таблица налогов)

Выглядит привлекательно. На первый взгляд это выглядит так, как будто есть
пять взаимоисключающих возможностей: (а) таблица налогов, (Ъ) налоговая та­
рифная сетка, (с) бланк D, (d) форма 8615 или (е) форма 8814. Однако, изучая
формы 8615 и 8814, я замечаю, что они могли бы представлять собой две дополни­
тельные позиции для каждой из первых трех опций. Я пытался получить объясне­
ния в ВПС, но не получил. Я позвонил моему бухгалтеру, и он спросил, будет ли это
«специальной консультацией», но я ответил: «Не беспокойся, Чарли». Такого рода
исследования вы можете проводить при создании практической модели, но в этом
примере я буду рассматривать пять различных вариантов.
38 38.2 t a x ra te sc hedule (налоговая тарифная сетка)
38.3 Бланк С
38.4 Форма 8615
38.5 Форма(ы) 8814

Заметим, что может быть несколько форм 8814, но мы не говорим о том, что­
бы суммировать эти формы. Такие особенности должны быть исследованы. Здесь
нам следует взять вместе все формы 8814, так как они должны быть заполнены на
каждого ребенка, чей интерес и дивиденды вы представляете при заполнении нало­
говой декларации.
38.1 39 налог в соответствии с t a x t a b l e (таблицей налогов)
38.2 39 налог в соответствии с t a x r a t e sc hedule (налоговой тарифной
сеткой).
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
3.4. Методика 77

Я смоделировал это именно таким образом, так как из налоговых форм мне по­
казалось, что можно облагать налогом по форме 4970 или 4972 или сразу по обеим.
Такие вещи не очевидны, и вы должны их исследовать.
39.5 40 Ничего не делайте
40 41 Добавьте строки 39 и 40

Ужасно? Построение такой модели с простой на вид спецификацией стоило


многих усилий. Это заняло у меня пять часов, включая время, затраченное на ри­
сование презентабельных фрагментов графа и пояснительные комментарии, ко­
торые я бы и не делал, если бы я создавал настоящий план тестирования. Но все
эти комментарии и внутренние монологи —это неплохая идея. Кто-нибудь (вроде
вас), может быть, поблагодарит за это.
Исходя из опыта и практики, на построение данной модели должно затрачи­
ваться максимум два-три часа. При большем объеме исследования это, вероят­
но, займет больше времени. Заметим, что мои графические модели по ходу дела
становились проще. В последней модели, например, детализирован только поток
управления. Это сделано преднамеренно. Вы используете графические формы
для того, чтобы быть уверенным в правильности логики, однако вам также необ­
ходимо документировать детали содержания в виде списка.
По ходу дела я менял обозначения. Граф, который мы рассматривали в пункте
3.1, имеет формат иня узла/действие/значение предиката, тогда как последний фор­
мат это имя_узла/имя_узла/действие или значение предиката/коннентарии. Опираясь на
последние обозначения, связи легко отметить и контролировать, но более ранние
обозначения ближе к первоначальной форме изложения. При этом не имеет зна­
чения, какой формат вы используете. Выберите что-то одно, что имеет все необхо­
димые данные и чего вы можете придерживаться.
Другая причина состоит в том, что это не программирование. Я не пытался
использовать структурированное мышление, при этом мои модели полны GOTO и
подобных ему вещей. В настоящее время при реализации явной логики обычно
ограничиваются строго структурированными конструкциями. Я здесь предпочи­
таю GOTO и другие бесструктурные вещи, так как при этом не надо далеко отхо­
дить от естественного языка спецификации. Большинство естественно-языковых
спецификаций бесструктурно. Если вы слишком отдаляетесь от первоначальной
формулировки для принудительного использования, скажем, вложенного дере­
ва IF-THEN-ELSE, то увеличивается вероятность ошибки моделирования, которая,
в свою очередь, приводит к тестовым ошибкам или необнаруженным ошибкам
программы.

3.4.3. Выбор путей тестирования


3.4.3.1 Основы
Вы ничего не выиграете, уменьшая количество тестов. Лучше использовать про­
стые, очевидные тесты, чем выполнять работу с меньшим количеством более гро­
моздких тестов. Предыдущий пример можно, вероятно, сжать до 10 тестов, но нам
следует использовать большее их число, если при этом тестирование проходит
максимально чисто и больше согласовано с требованиями.
78 Глава 3 • Тестирование потока управления

Очень часто выбор путей тестирования и их активизацию выполняют одно­


временно, так как корреляция предикатов может воспрепятствовать проходу про­
граммы по произвольно выбранным путям. Хотя это и хорошо на практике, ди­
дактически это неправильно, поэтому мы сначала выберем пути тестирования,
а затем, в следующем разделе, будем их активизировать.
Мы создаем путь, добавляя сегмент за сегментом, начиная с входного узла
и продолжая до выходного узла. Мы выбираем наши сегменты, начиная с точек,
где потоки управления расходятся из одиночного узла, и продолжаем до тех пор,
пока потоки управления опять не сойдутся в один узел. Примеры: 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(И). 33а5. ЗЗаб
А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(Л). ЗЗаЮ. ЗЗЬ
3.4. Методика 79

Следующий предикат —это узел ЗЗЬ. Вначале я допустил ошибку и в результа­


те получил проблемы с активизацией. Я не забегаю вперед, чтобы увидеть, может
ли этот предикат заблокировать дальнейшие пути, завершаемые в сегменте 34-35.
Вот два варианта для этого сегмента: В1: ЗЗЬ(И), ЗЗЫ, 33с и В2: ЗЗЬ(Л), 33с.
Я не знаю, какие комбинации блокируются позже, поэтому в этой точке создаю
четыре варианта, комбинируя наборы А и В. Позднее мы исключим тесты, кото­
рые не выполняются. Получаем следующее семейство тестов.
В1А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И). 33а9.
ЗЗаЮ. ЗЗЬ(И). З З Ы . 33с
В2АК 32. 33а 1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И), 33а9,
ЗЗаЮ, ЗЗЬ(Л). 33с
В1А2: 32. 33а1. ЗЗа2(Л), ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). 33а10. ЗЗЬ(И). З ЗЫ .
33с
В2А2: 32. 33а1, ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). 33а10. ЗЗЬ(Л). 33с

Следующий сегмент — это 33с-34. Существует пять возможных путей через


этот сегмент, и все пять необходимы для покрытия связей. Пять сегментов:
С1: З З с (Л ) . ЗЗс2(И). ЗЗсЗ. 34
С2: ЗЗс(И), ЗЗсКИ ). ЗЗсЗ. 34
СЗ: ЗЗс(И). ЗЗсКЛ). З Зс 4(И ). ЗЗсЗ. 34
С4: З З с (Л ) . 33с2(Л). 34
С5: ЗЗс(И). ЗЗсКЛ). З Зс 4 ( Л ) . 34

Здесь целесообразна быстрая проверка. Я просмотрел четыре предиката (33с,


33с1, 33с2 и 33с4) в предыдущем списке, чтобы быть уверенным, что каждый преди­
кат принимает оба значения (ИСТИНА и ЛОЖЬ) в каком-нибудь сегменте теста.
С1В1А1: 32. 33а1. ЗЗа2(И), ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10. ЗЗЬ(И). З З Ы . ЗЗс(Л). ЗЗс2(И). ЗЗсЗ. 34
С2В1А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10. ЗЗЬ(И). З З Ы . ЗЗс(И). З З с К И ) . ЗЗсЗ. 3 4 -
СЗВ1А1: 32. 33а1. ЗЗа2(И), ЗЗаЗ. ЗЗа4(И), 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10. ЗЗЬ(И). З З Ы . ЗЗс(И). З З с К Л ) . ЗЗс4(И). ЗЗсЗ. 34
С4В1А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10. ЗЗЬ(И). З З Ы . ЗЗс(Л). ЗЗс2(Л). 34
С5В1А1: 32. 33а1. ЗЗа2(И), ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И),
33а9. 33а10. ЗЗЬ(И). З З Ы . ЗЗс(И). З З с К Л ) . ЗЗс4(Л). 34
С1В2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10, ЗЗЬ(Л). Зс(Л). ЗЗс2(И). ЗЗсЗ. 34
С2В2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. 33а10, ЗЗЬ(Л). ЗЗс(И). З З с К И ) . ЗЗсЗ. 34
СЗВ2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. ЗЗаЮ. ЗЗЬ(Л). 33с( И). З З с К Л ) . ЗЗс4(И). ЗЗсЗ. 34
С4В2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. ЗЗаЮ. ЗЗЬ(Л). ЗЗс(Л). ЗЗс2(Л). 34
С5В2А1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5, ЗЗаб(И). 33а7. ЗЗа8(И).
33а9. ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И). З З с К Л ) . ЗЗс4(Л). 34
С1В1А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И). З З Ы .
З З с (Л ) . 33с2 (И). ЗЗсЗ. 34
С2В1А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И). З З Ы .
33 с(И). З З с К И ) . ЗЗсЗ. 34
СЗВ1А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И). З ЗЫ .
ЗЗс(И). З З с К Л ) . ЗЗс4(И). ЗЗсЗ. 34
С4В1А2: 32. 33а1, ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л), ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И). З ЗЫ .
80 Глава 3 • Тестирование потока управления

З З с ( Л ) , З Зс 2(Л ). 34
С5В1А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И). З З Ы .
ЗЗс(И). З З с К Л ) . ЗЗс4(Л). 34
С1В2А2: 32. 33а1. ЗЗа2(Л), ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ, ЗЗЬ(Л).
З З с (Л ) . З Зс 2(И ). 33с3. 34
С2В2А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
33с( И). 33с1(И). ЗЗсЗ. 34
СЗВ2А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
33 с( И). З З с К Л ) . З Зс4(И ). ЗЗсЗ. 34
С4В2А2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л), ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
ЗЗс(Л). З Зс 2(Л ). 34
С5В2А2: 32. 33а1. ЗЗа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(Л). 3 4 .2 ( Л). 34.3(H ). 34.4, 34.12
D4: 3 4 (Л ) . 3 4 .2 ( Л). 34.3(Л), 34.5(H). 34.6. 34.12
D5: 34(Л). 3 4 .2 ( Л). 34.3(Л ), 34 .5(Л), 3 4 . 7(Х0Л0СТ). 34.8. 34.12
D6: 3 4 (Л ) . 3 4 .2 ( Л). 3 4 .3(Л ). 34.5(Л). 3 4 .7(ГЛАВА). 34.9. 34.12
07: 34 (Л ) . 3 4 . 2 ( Л ) . 34.3(Л ). 34 .5(Л). 3 4 .7 ( СОВМЕСТНО). 34.10. 34.12
08: 34 (Л). 34.2 (Л). 3 4 . 3 Ш , 34 .5(Л). 34.7 (РАЗДЕЛЬНО). 34.11. 34.12

Если мы продолжим комбинирование, то у нас получится 20 вариантов, скомби­


нированных с восемью вариантами. То есть всего 160 вариантов для рассмотрения.
Поэтому стоит исключить некоторые варианты по ходу рассмотрения. Это еще одна
причина, почему активизация и выбор пути обычно выполняются вместе.
Мы исключаем пути посредством удаления комбинаций, которые не могут
быть выполнены, так как предикаты блокируют друг друга. Я создал таблицу из
20 строк и 8 столбцов (табл. 3.2). Заголовками строк были сегменты сС1В1А1по
С5В2А2, а заголовками столбцов —сегменты от D1 до D8.
la. Значение ЛОЖЬ в узле 34.5 означает, что графа 33с не была помечена, по­
этому путь не может пройти через узел ЗЗсЗ, соответствующий помеченной
графе. Я использовал текстовый редактор, чтобы найти те сегменты, кото­
рые содержат в себе узел ЗЗсЗ. Это оказались С 1, С2 и СЗ. Их нельзя ском­
бинировать с D5-D8, так как в этих вариантах должна быть помечена графа
ЗЗсЗ. Поэтому следует вычеркнуть их из таблицы.
lb. Напротив, значение ИСТИНА в узле 34.5 означает, что графа 33с была по­
мечена, поэтому путь проходил через узел ЗЗсЗ. Следовательно, D4 не ком­
бинируется с С4 и С5.
2а. Если графа 33b помечена, логика не позволяет выбрать в узле 34.3 исходя­
щую ветвь, соответствующую значению ЛОЖЬ. Следовательно, если вы­
полняется узел ЗЗЫ, сегменты D4-D8 выполняться не могут. Используя
3.4. Методика 81

поиск по узлу ЗЗЫ (где проверяется пометка графы ЗЗЬ), мы видим, что лю­
бой сегмент, включающий вариант В1, не может быть скомбинирован с сег­
ментами D4-D8.
2Ь. И наоборот, если графа ЗЗЬ не помечена (вариант В2), логика не позво­
ляет выбрать в узле 34.3 исходящую ветвь, соответствующую значению
ИСТИНА, и вариант D3 не может объединяться с любыми путями, кото­
рые включают ЗЗЬ(Л). Это пути, содержащие в себе В2. Поэтому любые сег­
менты с В2 не комбинируются с D3.
За. Если графа 33а помечена, тогда сегменты D3-D8 можно удалить. Графа 33а
помечается в узлах ЗЗаЗ, 33а5, 33а7 и 33а9. Проводя заново поиск наших
сегментов, мы видим, что это любые сегменты, содержащие А1. Поэтому А1
не комбинируется с D3-D8.
Таблица 3.2. Определение графа состояний
СЕГМЕНТ D1 D2 D3 D4 D5 D6 D7 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 хххх хххх хххх хххх хххх хххх хххх

ЗЬ. Наоборот, если графа 33а (А2) не помечена, то можно не учитывать D2.
4а. Если вы женаты и заполняете форму раздельно (проверяется 33с), то вы не
можете заполнять форму совместно в 34.7. Следовательно, любые сегмен­
ты С1В1А1-С5В2А2, включающие ЗЗс(И), не могут комбинироваться с D7.
Это все сегменты, содержащие С2, СЗ или С5.
4Ь. И наоборот, любой сегмент, содержащий С1 или С2, не может комбиниро­
ваться с D8. Так как ЗЗс(Л ) не означает заполнение раздельных деклараций
и 34.7 (РАЗДЕЛЬНО) этому противоречит.
82 Глава 3 • Тестирование потока управления

5. Если вы холосты (34.7(XOJIOCT)-D5), или вы глава хозяйства (34.7


(ГЛАВА)-Вб), льготы вашего супруга не могут быть детализированы.
Следовательно, сегменты с ЗЗс1(И)-С2 не могут комбинироваться с сег­
ментами D5 или D6. Это нам ничего не дает, но, между прочим, мы уже ис­
ключили 116 вариантов из 160 возможных.
6а. Мы знаем, годами заполняя совместную налоговую декларацию, что если
ваши льготы детализированы, то льготы вашего супруга должны детализи­
роваться и наоборот. Следовательно, любые варианты с ЗЗс1(Л)-СЗ и С5
не сочетаемы с 34(H)-D1, и исключается более восьми случаев.
6Ь. Двигаясь в обратном направлении, мы можем понять, что С2 не может ком­
бинироваться с D2-D8.
7. Если вы женаты, заполняете форму раздельно, и льготы вашего супруга не
детализированы, и он не является иностранцем (С5), вы не можете быть хо­
лосты (D5) или быть главой хозяйства (D6).
Сейчас мы можем продолжить выбор путей. Рассматривая неотмеченные ячей­
ки в таблице, видим, что для D5, D6, D7 и D8 вариантов нет. Они должны комби­
нироваться соответственно с С4В2А2, С4В2А2, С4В2А2 и С5В2А2.
D5C4B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
З З с ( Л ) . З Зс 2(Л ). 3 4 (Л ) . 34.201). 3 4 . 3 Ш . 34 .5(Л). 34.7 ( ХОЛОСТ).
34.8. 34.12
D6C4B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
З З с (Л ) . ЗЗс2(Л).34(Л). 34.201). 34.301). 34.501). 34.7(ГЛАВА),
34.9. 34.12
D7C4B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
33с 01). З Зс 2(Л ). 3401). 34.201). 34.301). 34.5(Л).
3 4 . 7 (СОВМЕСТНО). 34.10. 34.12
D8C5B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
ЗЗс(И). З З с К Л ) , ЗЗс4(Л ). 34(Л). 34.201). 34.301). 34.501).
3 4 .7 (РАЗДЕЛЬНО). 34.11. 34.12

У нас есть три варианта для D4. В данный момент я возьму вариант С1, приво­
дящий к D4C1B2A2.
D4C1B2A2: 32. 33а1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(Л).
З З с (Л ) . ЗЗс2(И ). ЗЗсЗ. 3 4 (Л ). 3 4 .2(Л ). 34.3(Л). 34.5(H). 34.6.
34.12

В этом месте мы еще должны включить Al, Bl, С2, СЗ, Dl, D2 и D3. D3 может
сочетаться только с комбинацией В1А2, поэтому давайте скомбинируем В1А2 с
СЗ, для того чтобы получить в итоге СЗВ1А2 с D3.
D3C3B1A2: 32. 33а 1. ЗЗа2(Л). ЗЗа4(Л). ЗЗаб(Л). ЗЗа8(Л). ЗЗаЮ. ЗЗЬ(И).
З З Ы . ЗЗс(И). З З с К Л ) . ЗЗс4(И ). ЗЗсЗ. 34(Л). 3 4 .2(Л). 34.3(H).
34.4. 34.12

Сейчас мы должны включить Al, С2, D1 и D2. D2 не комбинируется с С2, поэ­


тому давайте скомбинируем ее с СЗВ2А1.
D2C3B2A1: 32. 33а1. ЗЗа2(И). ЗЗаЗ. ЗЗа4(И). 33а5. ЗЗаб(И). 33а7. ЗЗа8(И).
33а9, ЗЗаЮ. ЗЗЬ(Л). ЗЗс(И), З З с К Л ) . ЗЗс4(И). ЗЗсЗ. 34(Л).
34.2(H ). 34.4. 34.12
3.4. Методика 83

В итоге закончим мы следующим путем:


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. Активизация
3.4.4.1. Основы
Активизация. Поиск входных значений, при которых (в случае отсутствия в реа­
лизации ошибок) в модели будет пройден выбранный путь.
Большая часть тех процедур, которые описывались в предыдущем разделе, яв­
лялись активизацией логики в моделях. Процедура активизации зависит от пре­
дикатов, встречающихся в рассматриваемом пути. Если предикаты в большинстве
своем логические, как это было в предыдущем разделе, тогда активизация и выбор
пути осуществляются одновременно. Если предикаты в большинстве своем чис­
ленные (то есть алгебраические), то данные процедуры различаются, что описы­
вается в подразделе «Алгебраическая активизация».
Знание приложения важнее знания алгоритма активизации. Знание того, что
приложение будет делать в том или ином случае, существенно для определения
набора путей, обеспечивающих полное покрытие, и входных значений для их ак­
тивизации. Я уверен, что если бы мы были экспертами в области налогообложе­
ния, нам было бы гораздо легче найти для предыдущего примера набор путей,
обеспечивающих покрытие. Прежде чем вы потратите силы и время на активиза­
цию, запустите простейшие тесты вашей модели и убедитесь, что она обеспечива­
ет покрытие связей. После этого у вас останется совсем немного мудреных путей,
требующих для активизации применения формальных методов.
84 Глава 3 • Тестирование потока управления

Если при активизации пути возникли непреодолимые трудности, то они мо­


гут объясняться одной из следующих причин: путь непроходим, модель содер­
жит ошибки или спецификация содержит ошибки. Проверьте эти предположе­
ния, прежде чем потратить массу времени на бесполезную работу.
3.4.4.2. Логическая активизация
Ниже приведен обзор процедур, которые мы должны сделать для выбора (и акти­
визации) пути.
1. Разбейте модель на сегменты, начинающиеся и заканчивающиеся на оди­
ночном узле. В примере, приведенном в разделе 3.4.3 «Выбор путей тести­
рования», такими сегментами были: 32-33а4, 33а4-33а6, 33а6-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. Выберите два любых сегмента с коррелированными предикатами, даже
если они не соединены напрямую, начните с тех пар сегментов, которые со­
держат идентичные предикаты. Вам нужна строгая корреляция. Например,
сегмент, в котором задается условие, и следующий сегмент, в котором это
условие проверяется. Сегмент ЗЗЬ-ЗЗс помечает графу ЗЗЬ, впоследствии
это проверяется в узле 34.3 сегмента 34-34.12.
5. Исключите методом от противного непроходимые пути. Установите значе­
ние предиката в первом сегменте равным ИСТИНА и устраните все отрез­
ки пути во втором сегменте, на которых коррелированный предикат прини­
мает значение ЛОЖЬ. Затем положите значение первого предиката равным
ЛОЖЬ и устраните все отрезки пути во втором сегменте, на которых кор­
релированный предикат принимает значение ИСТИНА. Будьте, однако,
внимательны, так как отрицание последовательности предикатов в виде
A&B&C&D... эквивалентно логической сумме отрицаний этих предикатов,
то есть НЕ А ИЛИ НЕ В ИЛИ НЕ С ИЛИ НЕ D... Используйте для уверен­
ности в верности преобразований булеву алгебру.
6. Продолжайте выполнять операции, описанные в пункте 5, объединяя сег­
менты и устраняя по ходу их комбинации. Таким образом, вы построи­
те более длинные пути, содержащие коррелированные предикаты. При
объединении сегментов (например, 33с-34/34-34.12) вы создаете более
длинные сегменты, хотя и с меньшим числом возможных путей в каждом
из них.
3.4. Методика 85

7. На данном этапе у вас уже есть набор больших сегментов, которые не кор­
релируют друг с другом. Это означает, что вы можете выбрать отрезки пути
в каждом из сегментов, которые не зависят от других сегментов. Выберите
достаточное число путей в каждом сегменте, чтобы быть уверенным, что вы
обеспечили покрытие связей внутри этих сегментов.
8. Объединяйте сегменты, комбинируя пути и выбирая имеющие смысл ком­
бинации. Обратите внимание, что число тестов при этом не должно увели­
читься. Например, сегмент А содержит 6 путей, а сегмент В — 10 путей. Это
означает, что пара сегментов будет содержать 10 путей, а не 60. Поскольку
сегменты некоррелированные, вы можете связать любой отрезок пути в сег­
менте А с любым отрезком пути в сегменте В.
9. Продолжайте до тех нор, пока не получите набора путей, обеспечивающих
покрытие.
10. Теперь мы можем перейти непосредственно к активизации. Следуйте вдоль
пути и по достижении предиката определите входное условие, при кото­
ром предикат принимает значение ИСТИНА или ЛОЖЬ, в зависимости
от требований пути. Вам, возможно, придется использовать некоторые ме­
тоды из следующего раздела для осуществления этого, однако, как правило,
для большинства логических предикатов и предикатов выбора, это должно
быть просто, так как вы уже убедились в отсутствии противоречий на вы­
бранном пути.
3.4.4.3. Алгебраическая активизация
Интерпретация предиката. Предикат считается интерпретированным, если он
выражен через входные значения. Интерпретация предиката зависит от выбора
пути. Это означает, что мы можем получить эквивалентный предикат, следуя в
вычислениях по определенному пути, ведущему к этому предикату.
Примером в данном разделе служит расчет детализированных льгот в Бланке А,
строке 29 (См. Приложение). Модель для этого вычисления приводится ниже. Это
не полная модель —она содержит только узлы, находящиеся на пути, который мы
активизируем. Переменные, начинающиеся с буквы А, относятся к бланку А или
к строкам формы 1040. Переменные, начинающиеся с буквы W, относятся к про­
цедуре расчета.
1 1.1 in p u t AL4
1.1 1.2 in p u t AL9
1.2 1.3 in p u t AL14
1.3 1.4 in p u t AL18
1.4 1.5 in p u t AL19
1.5 1.6 in p u t AL26
1.6 1.7 inpu t AL27
1.7 1.8 in p u t AL28
1.8 2 W1 = AL4 + AL9 + AL14 + AL18 + AL19 + AL26 + AL27 + AL28
2 2.1 in pu t AL13
2.1 2.2 in p u t AL28g
2.2 3 W2= AL4 + AL13 + AL19 + AL28g
3 3.1 W3= W2-W1
86 Глава 3 • Тестирование потока управления

W3 = AL4 + AL9 +AL14 + AL18 + AL19 + AL26 + AL27 + AL28 -


(AL4 + AL13 + AL19 + AL28g)
W3 = AL8 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g
3 -i W tS vf- W3 <— 9
IF ALQ * ALII <--АЫ8 Afc26 ^AL-g-7 »■ -Afcg8---- Ab±3-----AL28g <- 0

Второй предикат на последней не зачеркнутой строке —это интерпретирован­


ный предикат. Сначала мы подставили входные значения, а затем выразили пре­
дикат через них путем их подстановки в символьном виде.
Нетрудно заметить, что спецификация в данном случае неверна. В ней гово­
рится: «если результат равен нулю...», а должно быть: «если результат меньше или
равен нулю...»
Я зачеркнул последнюю строку, поскольку активизация у нас выполняется
вдоль определенного пути. Мы будем рассматривать путь, определенный на стро­
ке 10. Продолжим модель:
3.1 4 IF AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g > О
4 5 0.8 * W3 = 0.8 * (AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 -
AL28g)
5 6 in p u t 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 v1— Ш . 6 ■ 1f-W7 < — О
8 i f W7> 0: i f AL32 - 55.900 > 0
8 9 W7* 0.03= AL32* 0.03 -1.6 67.0 0
9 -- 9т4-----F F AL32*-9-. 03----- Ь 667 . 0 0 ^ - 0 . 8 * (AL9 » AL14 > AL18 +-AL26-+-
AL27 ' AL28---- АН-3-----AL28g)
9.2 i f AL32* 0.03 -1.66 7.00 > 0.8 * (AL9 + AL14 + AL18 + AL26 +
AL27 + AL28 - AL13 - AL28g)
9.2 9.5 WL9 = 0.8 * (AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 -
AL28g)
9.5 10 WL10 = AL4 + AL9 + AL14 + AL18 + AL19 + AL26 + AL27 + AL28 -
0.8*(AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL II - AL28g)

Ниже приведены интерпретированные предикаты, через которые проходит


этот путь:
AL9 + AL14 + AL18 + AL26 + AL27 + AL28 - AL13 - AL28g > 0
РАЗДЕЛЬНОЕ ЗАПОЛНЕНИЕ
AL32 - 55.900 > 0

Это простой случай, поскольку все три предиката полностью независимы. Но


так бывает далеко не всегда. Как правило, входные значения встречаются сра­
зу в нескольких интерпретированных предикатах. Следует отметить, что здесь
указаны далеко не все существующие условия. Дополнительные условия: все
входные переменные должны быть больше или равны нулю. Строго говоря, вам
следует записывать такую информацию, чтобы не забыть ее на следующем шаге
активизации.
3.4. Методика 87

На следующем шаге активизации мы ищем набор входных значений, удовле­


творяющих всем интерпретированным предикатам на заданном пути. В послед­
нем примере это выполняется достаточно просто.
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, к примеру), и в результате получим набор согласованных
входных значений, удовлетворяющих всем интерпретированным предикатам на
заданном пути. Вот мой набор входных значений:
88 Глава 3 • Тестирование потока управления

AL9 = 10
AL18 = 15
AL26 = 30
AL27 = 40
AL13 = 5
AL28 = 10
AL14 = AL18 + 10
AL32 = 55.900

В большинстве случаев вы можете выполнить активизацию, не прибегая к фор­


мальному решению уравнений с использованием матриц и даже не подозревая о
том, что можно использовать эту процедуру. Начните с простейших неравенств,
где у вас есть наибольшая свобода выбора и выберите входные значения для них.
Потом подставьте эти значения в другие неравенства и упростите. Используйте
простейшую арифметику для исключения переменных, комбинируя выражения
путем их сложения и вычитания.
Если вы не можете обойтись простейшими подстановками и упрощениями, то,
прежде чем потратить время и силы на инвертирование матриц, проверьте специ­
фикации и свои предыдущие действия. Как правило, причины, толкающие вас на
инвертирование матриц, кроются в ваших предыдущих ошибках и/или в ошибках,
содержащихся в спецификации.
Другой способ решения данной проблемы —поместить ваши неравенства и вы­
ражения в электронную таблицу и использовать встроенные методы решения сис­
тем уравнений для получения ответа. Например, инструменты для решения урав­
нений в LOTUS-123 справятся с этим превосходно. Более того, они позволяют
смешивать логические и алгебраические предикаты в одном наборе неравенств.

3.4.5. Предсказание итогов


Следующим шагом в процессе проектирования теста является предсказание ито­
гов для каждого из выбранных путей. Хотя вашим первым побуждением будет по­
пытка сыграть роль компьютера и пройти по этим путям вручную, не спешите это
делать. Во-первых, это может быть очень непростой задачей. Во-вторых, вы бу­
дете пытаться заменить собой компьютер, а в этом еще никто из людей не преус­
пел. Вы с большей вероятностью допустите ошибку в вашем предсказании итогов,
чем программист в программе. Ниже приведено несколько более привлекатель­
ных альтернативных вариантов.
Существующие тесты. Около 80 % труда разработчиков программного обес­
печения на сегодняшний день уходит на сопровождение программ. Большинство
тестировщиков и программистов работает над модификацией уже существующе­
го программного обеспечения. Это означает, что 95 процентов ваших тестов не
меняется от версии к версии. Если вы будете так же тщательно контролировать
конфигурацию своих тестов, как и конфигурацию программного обеспечения, то
у вас будет оракул для большинства ваших тестов.
Старые программы. Серьезное обновление не всегда влечет за собой соответс­
твующие изменения в тестовом комплекте, поэтому старые программы могут ис­
пользоваться в качестве оракула. Например, старая программа была написана для
3.4. Методика 89

MS DOS. Теперь требуется перенести ее на другие платформы. Хотя подобная пе­


ределка программы может вести к полному ее переписыванию, старая программа
является превосходным оракулом. Запустите на ней свои тесты для нахождения
ожидаемых итогов.
Предыдущие версии. Даже если код, который вы тестируете, был переписан,
как правило, для большинства путей корректные итоги могут быть получены из
предыдущих версий программы. В худшем случае могут быть внесены изменения
в небольшое количество путей, однако разница в итогах тестов для старой и новой
версий программы легко прогнозируется. Используйте итоги, полученные для
предыдущей версии, как отправную точку для поиска итогов для соответствую­
щих путей в новой версии.
Прототипы и модельные программы. Вы можете построить прототип, до­
статочно подробный для того, чтобы получить с его помощью корректные ито­
ги [STAK89], Хорошие прототипы, как правило, не лишены функциональности.
Причина, по которой они не могут служить рабочей программой, кроется в том,
что они или слишком медленные, или слишком большие, или просто не могут ра­
ботать в заданной операционной среде.
Если у вас нет детально проработанного прототипа, вы можете получить
оракула, построив модельную программу. Например, если бы мне надо было
написать программу для заполнения декларации о подоходном налоге, я бы на­
чал с того, что запрограммировал все формы в электронных таблицах, а алгеб­
ру и логику — на каком-нибудь простом языке, например, BASIC. Это не то же
самое, что писать код для реального продукта, поскольку вы не забиваете себе
голову вещами, о которых должен заботиться программист, такими, как доступ
к структурам данных, взаимодействие с операционной системой, ввод и вывод.
В большинстве стандартных программных продуктов предусмотрено много ве­
щей, не имеющих непосредственного отношения к прикладной задаче. Я не рас­
полагаю точными цифрами, но полагаю, что менее 10 процентов программного
кода имеют непосредственное отношение к прикладной задаче. Более того, эти
10 процентов кода зачастую являются наиболее простыми. Таким образом, пос­
троение модельных программ и использование их в качестве оракула не лише­
но смысла.
Выбор простых вариантов. Иногда существует возможность выбрать входные
значения так, чтобы они, с одной стороны, активизировали нужный нам путь, а
с другой — упрощали вычисления. Например, установить все входные значения,
кроме нескольких, равными нулю. В примере, приведенном выше, мы могли вы­
полнить все условия при помощи подбора значений AL9, AL18 и AL13. Остальные
входные величины мы могли положить равными нулю.
Вы можете возразить, что ситуация, когда на входе может быть так много ну­
лей маловероятна, но это плохой аргумент. В тестировании существует неписа­
ное (и неудачное) правило, гласящее, что входные значения должны быть реалис­
тичны. Реализм — это установка, мешающая хорошему тестированию. Реализм
нужен для демонстраций, но он не является целью тестирования. Реалистичные
тесты, хотя и кажутся убедительными, как правило, на поверку оказываются сла­
быми, поскольку именно их программист с большой вероятностью выполнит сам.
90 Глава 3 • Тестирование потока управления

Реализм не слишком хорош при поиске ошибок, а первоочередной задачей тести­


рования является как раз поиск ошибок, а совсем не создание иллюзии доступнос­
ти для простого человека.
Если вы включили в свой допустимый набор входных значений такие мало­
вероятные значения, как ноль, вы можете обнаружить, что предсказание ито­
гов, интерпретация предикатов и последующая активизация становятся проще.
Поскольку нереалистичные тесты, как правило, отличаются от тестов, проводи­
мых программистами, они с большей вероятностью могут выявить ошибки.
Конечная программа. Вы можете использовать конечную программу в качес­
тве оракула, если вы в ней уверены. Обычно проще проверить правильность ито­
га, чем вычислять его самому, подменяя собой компьютер. Это особенно касается
случаев, когда вы можете вывести на печать и проверить промежуточные значе­
ния величин. Под словом «уверены» я подразумеваю, что вы проводите анализ,
подтверждающий корректность итогов. Если вы просто принимаете итоги как они
есть, без проверки, вы, мягко говоря, ошибаетесь.

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. Рассмотрение приложения 91

Детализированные
льготы? Бланк А

Давайте посмотрим теперь на проблему проверки соответствия пути в пер­


спективе. Проверка необходима из-за угрозы возникновения случайной коррект­
ности. С другой стороны, поведенческое тестирование потока управления далеко
не единственный метод, который вам придется использовать. Поэтому проверяй­
те в пути все, что можете проверить. То есть если промежуточные элементы обра­
ботки легко доступны и у вас есть инструменты тестирования для проверки соот­
ветствия пути, программисты будут рады сотрудничеству с вами и помогут вам,
используя эту защиту от ошибок.
Другой приемлемый способ защиты от случайной корректности —это тестиро­
вание нескольких вариантов для одного и того же пути. Мы к этому придем, рас­
сматривая в дальнейшем другие методы тестирования, и особенно тестирование
доменов.

3.5. Рассмотрение приложения


3.5.1. Индикаторы приложений
Поведенческое тестирование потока управления применимо практически к лю­
бой программе и эффективно для большинства приложений. Это фундаменталь­
ный метод. Его используют обычно для тестирования относительно небольших
программ или сегментов больших программ. Как будет видно из примеров, при­
веденных ниже, он, скорее всего, будет эффективен для индивидуальных форм
ВНС, но использовать его для тестирования всего пакета налоговых документов
было бы затруднительно. Эти трудности объясняются тем, что модель получает­
ся слишком громоздкой, а, следовательно, выбор пути и активизация настолько
сложны, что результат не оправдывает затраченных усилий.
92 Глава 3 • Тестирование потока управления

3.5.2. Предположения об ошибках


Причиной большинства ошибок в программе могут являться ошибки потока
управления, и, следовательно, возникающее при этом аномальное поведение мо­
жет быть обнаружено путем тестирования потока управления. Однако основное
предположение об ошибках, на поиск которых направлено тестирование потока
управления, —это влияние ошибок на предикаты потока управления или то, что
поток управления сам по себе неправилен. В качестве примера можно привес­
ти ошибку в вычислении элемента, который в дальнейшем будет использоваться
как часть предиката потока управления, например, использование >= вместо <.
Примером грубой ошибки в потоке управления является ошибочное соединение
узла 34.4 с узлом 34.14 вместо 34.12. Подобные грубые ошибки в потоке управле­
ния сейчас встречаются довольно редко благодаря использованию языков струк­
турного программирования. В старом программном обеспечении, написанном на
языке COBOL, или, скажем, ассемблере, подобные ошибки встречаются значи­
тельно чаще.
Ошибки в вычислениях, не влияющие на поток управления, также можно ис­
кать с помощью рассматриваемого метода, однако для этих целей существуют луч­
шие методы. Тестирование доменов (см. глава 7) и тестирование потоков данных
(см. глава 5) более эффективны при поиске подобных ошибок.

3.5.3. Ограничения и предостережения


Ниже приведены некоторые ограничения и предостережения.
1. Вам не имеет смысла заниматься поиском отсутствующих требований, за
исключением, конечно, того случая, когда ваша модель включает в себя эти
требования, а программа —нет.
2. Вероятность того, что вы обнаружите неуместные или побочные характе­
ристики, отсутствующие в требованиях, но присутствующие в программе,
мала.
3. Чем лучше программист выполнил свою работу по тестированию модуля,
тем менее вероятно, что данный метод обнаружит новые ошибки, например,
если именно этот метод использовался при тестировании модуля (неплохая
идея).
4. У вас мало шансов найти пропущенные пути и характеристики в программе,
если программа и модель, на которой основывался тест, были написаны од­
ним человеком. Если вы программист и используете этот метод для тести­
рования своего собственного программного обеспечения, то неверное пред­
ставление, которое привело в итоге к потере путей и характеристик в вашей
программе, может остаться у вас в голове и когда вы проектируете тесты.
Если тесты разрабатывает кто-то другой, вероятность одинаковых ошибок
уменьшается, хотя и за счет увеличения затраченных усилий.
3.6. Резюме 93

5. Для устранения хотя и небольшой, но все же существующей угрозы возник­


новения случайной корректности вам надо проверить все промежуточные
вычисления и значения предикатов.
6. Ваши тесты не лучше вашего оракула.

з. 5.4. Автоматизация и инструментальные средства


На момент написания этой книги не существовало коммерческих инструментов,
предназначенных для работы с поведенческим тестированием потока управления,
однако большое количество инструментов поддерживает структурное тестирова­
ние потока управления. Вы можете использовать эти инструменты, запрограм­
мировав ваши модели на поддерживаемых языках, таких как С, Pascal или Basic
[DAIC93, GERH88, SCHI69, WARN64J. Это не будет потерей времени или избы­
точным программированием. Работа, затраченная на создание достаточно деталь­
ной графической модели, —это большая часть всей работы по представлению по­
луформальной модели в виде программы.
Причина, по которой программирование модели не является избыточным,
и, конечно, отличается от программирования реального продукта, заключается
в том, что вы не забиваете себе голову практическими вещами, такими как доступ
к базам данных, взаимодействие с операционной системой, ввод и вывод, вопросы
окружения и многим другим, порождающим реальные ошибки. В модельной про­
грамме могут отсутствовать детали, она не обязана работать на какой-то конкрет­
ной платформе, ей не обязательно быть производительной, и, что самое главное,
она не должна быть интегрирована с другими частями продукта.
Как используется модель? Вовсе не для запуска тестов реальной программы.
Именно программа должна быть протестирована, а не какая-то модель тестиров­
щика. Это так! Тестирование модели отличается от тестирования реальной про­
граммы, но его тоже надо проводить. Как вы собираетесь отлаживать свои тесты?
Модель надо использовать как инструмент, помогающий вам разработать набор
тестов, обеспечивающих покрытие, для выбора и активизации путей, в качестве
оракула для реального программного обеспечения. Если вы построили действу­
ющую модель, то вы можете применить к ней коммерческие инструменты тести­
рования. А это значительно упростит вашу работу.

3.6. Резюме
Поведенческое тестирование потока управления рассмотрено как фундаменталь­
ная модель тестирования черного ящика. Она является основой для всех других
методов тестирования, обсуждаемых в этой книге, и впоследствии я буду считать,
что вы ее усвоили.
Проектирование тестов начинается с создания поведенческой модели графа
потока управления на основе документированных требований, таких как специ­
фикация. Представление в виде списка, как правило, более удобно, чем рисунки
графов, но маленькие графы помогают при проектировании модели.
94 Глава 3 • Тестирование потока управления

Составные предикаты в модели следует устранять или заменять, например, эк­


вивалентными графами, для того чтобы не прятать реальную сложность. Вместо
графа при моделировании составных предикатов, состоящих из более чем трех
компонентов, используйте таблицу истинности.
Разбейте вашу модель на отрезки, которые начинаются и заканчиваются оди­
ночным узлом, и отметьте взаимную корреляцию предикатов во всех сегментах.
Постройте ваши тестовые пути, комбинируя пути в сегментах и исключая непро­
ходимые пути. Используйте противоречия между предикатами для вычеркивания
отдельных комбинаций. Маловероятно, что эта методика приведет к непроходи­
мым путям, которые будет невозможно активизировать.
Выберите достаточное количество путей через модель, чтобы гарантировать
полное покрытие связей. Не волнуйтесь, если тестов окажется слишком много.
Начните с выбора очевидных путей, которые имеют прямое отношение к тре­
бованиям, и посмотрите, не можете ли вы таким способом добиться покрытия.
Возможно, вы получите не самые эффективные тесты, но это политически верное
решение. Расширьте эти тесты, рассмотрев столько путей, сколько надо для сто­
процентной гарантии покрытия связей.
Активизируйте выбранные пути, интерпретируя предикаты вдоль пути в тер­
минах входных величин. Интерпретированные предикаты дают набор условий
или уравнений (в действительности неравенств), так что любое решение этого
набора неравенств будет условием прохода но выбранному пути. Если активиза­
ция не очевидна, то перед тем, как вы потратите много времени на решение урав­
нений, проверьте, нет ли ошибок в спецификации или модели. Если условия все
же сложны, рассмотрите вариант использования коммерческой программы, пред­
назначенной для решения неравенств для активизации, такой как LOTUS 1-2-3.
Алгебраический пакет может помочь с интерпретацией предикатов.
Не забывайте о возможности случайной корректности и сотрудничайте с про­
граммистами для получения промежуточных численных выводов, которые необ­
ходимы для проверки пути. Дайте выражениям с предикатами высокий приори­
тет, но не настаивайте больше чем на одном значении для каждой связи в графе.
Продумайте программирование вашей модели с помощью реального языка
программирования, используйте запрограммированную модель при проектирова­
нии тестов.

3.7. Вопросы для самопроверки


1. Дайте определение следующих терминов: операция И, комплементарные
сегменты пути, составной предикат, граф потока управления, коррелиро­
ванные предикаты, независимые предикаты, объединяющий узел, логиче­
ская модельная программа, логический предикат, НЕ, ИЛИ, предикат, ин­
терпретация предиката, узел с предикатом, узел выбора, предикат выбора,
активизировать, простой предикат, разделение транзакций, таблица истин­
ности.
3.7. Вопросы для самопроверки 95

Во всех следующих примерах не надо моделировать побочные формы и ведо­


мости, определенные в инструкциях ВНС.
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, (Ь) часть И,
(с) часть III, (d) часть IV раздела В. Представьте, что вы можете исполь­
зовать короткий метод (часть III), если вы не пометили графы lb, 1с, или
96 Глава 3 • Тестирование потока управления

Id. В любом случае выводы (если они есть) направляются на соответствую­


щую строку формы 1040. Таким образом, вы можете не беспокоиться отно­
сительно форм 1040A, 1040NR 1041, и т. д.
15. Форма 3903, часть I, Employee Moving Expenses (Расходы на поездки слу­
жащего).
Тестирование
циклов

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

4.2. Основные термины


Внешние термины: приложение, массив, компоновка, группа, С, оператор BREAK,
сбор/воспроизведение данных, COBOL, код, компилятор, копировать, поврежде­
ние данных, отказ, отладка, отрицательное приращение, конец файла, ввод (цик­
ла), вычислять, выполнять, поле, файл, длина файла, FOR, GOTO, аппаратные сред­
ства, эвристический, реализация, положительное приращение, инициализировать,
внутренний цикл, целочисленный, итерация, ошибка границ в памяти, объедине­
ние, модель, вложенный цикл, операционная система, внешний цикл, указатель,
ошибка указателя, предусловие, процесс внутри цикла, обработка, программа,
программист, программирование, язык программирования, случайный, запись,
повторяющийся процесс, требование, время выполнения, поиск, программное
обеспечение, сортировка, спецификация, язык структурного программирования,
структурное программное обеспечение, завершать, передавать, истинное значе­
ние, значение, переменная, WHILE.
Внутренние термины: поведение, поведенческое тестирование, тестирование
черного ящика, ошибка, граф потока управления, тестирование потока управле­
ния, граф, модель на основе графа, цикл, связь, логический предикат, узел, имя4

4 Зак. 770
98 Глава 4 • Тестирование циклов

узла, объект, исходящая связь, путь, предикат, отношение, действенный тест,


предикат-переключатель, спецификация, структура, симптом, системное тестиро­
вание, тестовый вариант, тестирование модуля.
Цикл. Повторяющийся или итерационный процесс. Та часть модели-графа, ко­
торая содержит цикл. То есть повторяющееся имя узла хотя бы на одном пути.
Число повторений цикла. Число раз, которое повторяется цикл. При выходе из
цикла не спутайте это число с конечным значением переменной управления цикла,
если она существует (смотри ниже). Ошибочное принятие числа повторений цик­
ла за конечное значение переменной управления цикла — распространенный ис­
точник ошибок.
Детерминированный цикл. Цикл, число итераций которого известно до того,
как начнется выполнение цикла.
Недетерминированный цикл. Цикл, число итераций которого неизвестно до
того, как начнется выполнение цикла, или цикл, число итераций которого опреде­
ляется или изменяется внутри цикла по ходу выполнения.
Узел управления циклом. Узел с двумя и больше исходящими связями: для од­
ной связи цикл будет выполняться, а для другой не будет. На рисунке узел управ­
ления циклом отмечен как «20».

Узел выхода из цикла. Узел, который представляет предикат по крайней мере с


одним значением, вызывающим отмену выполнения цикла. Цикл может, к несчас­
тью, иметь более одного узла выхода. Узел 20 в только что приведенной модели —
узел выхода из цикла.
Узел входа в цикл. Узел, через который происходит вход в цикл. Цикл может
иметь более одного узла входа. Узел 10 на предыдущем рисунке —это узел входа
в цикл.
Предикат управления циклом. Предикат в узле управления циклом, значение
которого определяет, будет цикл выполняться или нет.
Переменная управления циклом. Любая переменная в предикате управления
циклом, значение которой влияет на (истинное) значение предиката управления
циклом —что определяет, будет цикл выполняться или нет.
Цикл с предусловием. Цикл, в котором предикат управления циклом вычисляет­
ся до того как выполняется какая-либо обработка внутри цикла. На рисунке узел
управления циклом —это узел 20, а между узлами 10 и 20 нет никакой обработки.
Вся обработка происходит на связи 20-10, так что это цикл с предусловием.

Обработка

обработки
4.3. Отношения и модель 99

Цикл с постусловием. Цикл, в котором предикат управления циклом вычисля­


ется после обработки. В циклах с постусловием обработка выполняется по мень­
шей мере один раз.

Нет
обработки

Цикл со смешанной проверкой. Цикл, в котором обработка происходит и до,


и после того, как вычислен предикат управления циклом1.

Обработка

Вложенные циклы. Два или более циклов — вложенные, если один полностью
содержится в другом. На следующем рисунке цикл 10-20-10 является вложен­
ным по отношению к циклу 5-25-5.

4.3. Отношения и модель


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

1 Пусть вас не сбивают с толку языки программирования и семантика конструкций типа опера-
юров FOR и WHILE. Почти любая комбинация детерминировапных/педетерминированиых циклов с
проверкой до/после/смеш апной может быть создана с помощью почти любой логической структуры.
Смотрите упражнения в конце главы.
100 Глава 4 • Тестирование циклов

Вы заметите, что в нижеперечисленных моделях циклов я не использую кон­


струкции структурного программирования, такие как FOR или WHILE, а использую
вместо них явные предикаты и GOTO для данных модельных циклов. Мы имеем
дело с моделями, а не с кодом. Я не ратую за отбрасывание конструкций FORи WHILE
в пользу GOTO. Я не использую структурные конструкции циклов в моделях, пос­
кольку они зависят от языка, в котором реализованы, и в некоторых случаях даже
от специфического компилятора для данного языка. Это особенно справедливо
для проблем с циклами со смешанной проверкой. И именно это приводит к ошиб­
кам циклов в коде и дизайне теста.
Отношение между узлами в данных моделях — предшествует. Однако я осо­
знанно не буду говорить ничего конкретного об оставшейся части модели. Здесь
примеры будут приводиться для моделей потока управления, но тестирование
цикла применяется и ко многим другим моделям (в том числе к тестированию
синтаксиса), в которых, несмотря на то, что объекты и отношения различны, при­
нципы тестирования остаются теми же.

4.3.2. Детерминированные циклы


В детерминированных циклах число повторений цикла известно до того, как бу­
дет выполняться первый оператор внутри цикла, и внутри цикла нет процесса, ко­
торый вызвал бы изменение этого числа.
20 30 lo o p _ c o n tro l = 0. птах = 10
30 40 loop_process
40 30 lo o p _ co n tro l =< птах. lo o p _ co n tro l « lo o p _ co n tro l + 1
50 lo o p _ co n tro l > птах
50 продолжить оставшуюся часть модели

Это пример цикла с постусловием. Предполагается, что переменная управле­


ния циклом loopcontrol не меняется процессом loopprocess на связи 30-40. Она
может использоваться процессом loop process, но этот процесс саму ее не меняет.
Узел 20 —входной узел цикла. Узел 40 —выходной узел цикла и вместе с тем узел
управления циклом. Несмотря на то, что я использовал простое положительное
приращение (loop_control = loop control +1), можно использовать практически
любую функцию, в том числе и отрицательное приращение, приращение на вели­
чину т, или даже некоторую функцию от 1oop_control.
Переменной управления циклом здесь является loop_control, чье максималь­
ное значение равно 10. Однако обработка будет выполнена 11 раз. Ниже дан при­
мер детерминированного цикла с предусловием.
20 30 lo o p _ co n tro l = 1. птах = 10
30 50 lo o p _ co n tro l > птах
40 lo o p _ co n tro l < = птах
40 30 lo o p_ pro ce ss, lo o p _ co n tro l -■ lo o p _ co n tro l + 1
50 продолжить оставшуюся часть модели

Следующий пример — пример цикла со смешанной проверкой, поскольку об­


работка цикла происходит и до, и после выходного узла цикла.
20 25 lo o p _ co n tro l = 1. птах = 10
25 30 A _p ro ce ssin g
4.3. Отношения и модель 101

30 50 lo o p _ co n tro l > птах


40 lo o p _ co n tro l > птах
40 25 B _ p ro ce ssin g . lo o p _ co n tro l = 1oop_control + 1
50 продолжить оставшуюся часть модели

В этой модели на каждом шаге обязательно выполняется A processing. На по­


следнем шаге выполнения, однако, обрабатываемый объект минует B processing.
Заметьте, что значение переменной управления циклом, loop control, различно
для процессов А и В. Циклов со смешанной проверкой следует избегать в специ­
фикациях, моделях и программном обеспечении, так как они уязвимы для оши­
бок. В языках структурного программирования смешанные циклы не могут быть
созданы случайно, перед их применением программисту следует хорошенько по­
думать. Один из аргументов в пользу использования структурированных цик­
лов — уход от ошибок, связанных со смешанными циклами. При построении мо­
делей старайтесь использовать явные циклы с постусловием и предусловием, а
циклы со смешанной проверкой применяйте только в тех случаях, когда они не­
обходимы для точного моделирования требований. Если цикл со смешанной про­
веркой необходим, то он должен быть тщательно протестирован из-за повышен­
ной вероятности наличия ошибок.
Поскольку в детерминированных циклах заранее известно число повторов,
циклические процессы с их использованием надо конструировать во всех следу­
ющих случаях: копирование файла с известным числом записей, обработка п пла­
тежных чеков, добавление колонки чисел, заполнение массива числами, передача
файла известной длины.

4.3.3. Недетерминированные циклы


Недетерминированные циклы отличаются от детерминированных тем, что коли­
чество проходов цикла неизвестно до его старта. Такое может произойти вследс­
твие трех основных причин: это число неизвестно, обработка внутри цикла меняет
переменную управления циклом (если она существует), внутри цикла обнаруже­
но условие, вызывающее преждевременное прекращение цикла.
20 30 читать следукнцую запись
30 40 обработать запись
40 20 Не Конец Файла (КФ)
50 КФ
50 продолжить оставшуюся часть модели

В вышеприведенном коде мы не знаем, как много записей имеет файл, следо­


вательно, процесс будет продолжаться, пока не будет достигнута запись КФ. Этот
пример уязвим в силу нескольких причин. Если файл содержит только запись
КФ, тогда эта запись будет обработана с возможными пагубными последствиями.
Другое слабое место проявляется в случае, если файл не содержит записей, даже
записи КФ. Если программа точно реализует данную модель, с такими файлами
цикл будет выполняться бесконечно.
20 30 1oop_control = 1. птах = 10
30 50 1oop_control > птах
40 lo o p _ co n tro l < = птах
102 Глава 4 • Тестирование циклов

40 45 обработка цикла
45 46 lo o p _ co n tro l = lo o p _ co n tro l + INT(3*RAND)
46 30 lo o p _ co n tro l = lo o p _ co n tro l + 1
50 продолжить оставшуюся часть модели

При обработке перехода 45-46 вышеприведенной модели из loop control каж­


дый раз вычитается случайное число от 0 до 2. Я выбрал этот очевидный при­
мер, но цели можно достигнуть и без использования случайных чисел. Дело в том,
что мы не можем определить, когда выполнение этого цикла будет закончено, —
если вообще когда-нибудь будет. Несмотря на то, что может показаться, будто кон­
струкция детерминирована, она, тем не менее, является недетерминированной.
20 30 lo o p _ co n tro l = 1. птах = 10
30 50 lo o p _ co n tro l > птах
40 lo o p _ co n tro l < = птах
40 45 обработка цикла
45 47 значение поля = 17
46 значение поля * 17
46 30 lo o p _ co n tro l = lo o p _ co n tro l + 1
47 30 lo o p _ co n tro l = nmax + 1
50 продолжить оставшуюся часть модели

Несмотря на то, что вышеприведенный фрагмент имеет вид детерминирован­


ного цикла, он таким не является. Предикат в узле 45 проверяет величину опреде­
ленного поля. Если эта величина равна 17, loop_control принимает значение, вы­
зывающее прекращение выполнения цикла. Если значение поля не равно 17, цикл
последовательно выполняется до значения птах. В последнем случае цикл явля­
ется детерминированным. Мне не обязательно изменять переменную управления
циклом, чтобы добиться этого. Например, следующий фрагмент делает то же са­
мое без изменения переменной управления циклом.
20 30 lo o p _ co n tro l = 1. птах = 10
30 50 lo o p _ co n tro l > птах
40 lo o p _ co n tro l < = птах
40 45 обработка цикла
45 50 Значение поля = 17
46 Значение поля * 17
46 30 lo o p _ co n tro l = lo o p _ co n tro l + 1
50 продолжить оставшуюся часть модели

Процессы с недетерминированными циклами включают: сортировку п запи­


сей, поиск файла, получение файла по каналу связи, решение системы уравнений,
объединение двух файлов.
Различие между детерминированным и недетерминированным циклами чрез­
вычайно важно. Недетерминированные циклы, как правило, чаще содержат ошиб­
ки по сравнению с детерминированными и потому должны более тщательно тести­
роваться. В языках структурного программирования конструкция FOR (например,
FOR I = 1 to loopmax DO...) предназначена для детерминированных циклов. Наоборот,
конструкция WHILE ... DO предназначена для недетерминированных циклов. Цикл
FOR имеет явную переменную управления циклом, цикл WHILE не имеет. Поскольку
циклы FOR могут быть недетерминированными, а циклы WHILE детерминированны­
ми, большинство программистов полагает, что выбор между ними — вопрос сти­
4.3. Отношения и модель 103

листики. Это приводит к ошибкам, в которых недетерминированные процессы ре­


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

4.3.4. Вложенные циклы


Вложенные циклы являются проблемными (то есть часто содержат ошибки). Они
содержат, конечно, обычные ошибки, которые можно ожидать в единичном цик­
ле (например, потерю первого варианта, слишком раннее прекращение, слишком
позднее прекращение, бесконечное выполнение), но также и ошибки, возника­
ющие в результате одновременного достижения условий прекращения в обоих
циклах. Например, рассмотрим следующий фрагмент кода.
20 30 o u ter_1 oop_ control = 1, outermax = 10
30 40 in n e r_ lo o p _ c o n tro l = 1. innermax = 100
40 45 обработка внутреннего цикла
45 30 in n e r_ lo o p _ c o n tro l < innermax. in n e r_ lo o p _ co n tro l =
in n e r_ lo o p _ c o n tro l + 1
50 in n e r_ lo o p _ c o n tro l > = innermax
50 55 обработка внешнего цикла
55 20 o ute r_lo o p _count < outermax. o u te rJ o o p _ c o n tro l =
o u te r_ lo o p _ c o n tro l + 1
60 o u t e r jo o p count > = outermax
60 продолжить оставшуюся часть модели

Что здесь произойдет при outer!oopcontrol = 10 и i nnerloop_control = 100, a


также при близких им значениях?

4.3.5. Неструктурированные (ужасные) циклы


Ужасные циклы имеют место в случаях, когда происходит прыжок (переход) из се­
редины или прыжок в середину цикла.
На следующем рисунке представлена эта печально известная структура, по­
скольку в ней присутствуют оба типа переходов. Связь 30-10 является прыж­
ком из цикла 20-30-40-20, в то время как связь 40-20 представляет собой ска­
чок в цикл 10-20-30-10. Циклы со смешанной проверкой не слишком ужасны,
поскольку в них происходит скачок из середины цикла. Другая проблема циклов
со смешанной проверкой заключается в том, что входной узел цикла для первой
итерации отличается от входных узлов цикла для последующих итераций.

Программисты должны стараться избегать создания ужасных циклов на язы­


ках структурного программирования, но такие циклы часто встречаются в старом
104 Глава 4 • Тестирование циклов

программном обеспечении, написанном на языке ассемблера и более старых язы­


ках программирования.
Для ужасных циклов нет хороших тестов. Как вы управитесь с ними, зависит
от того, откуда они взялись. Если они следствие способа, с помощью которого вы
построили модель, тогда смоделируйте ее заново, используя структурированные
циклы. Ужасные циклы могут быть корректной моделью поведения приложения,
особенно если, как в случае тестирования потока транзакций, вы создаете модель
человеческого поведения. Например, если вы моделируете поведение человека,
набирающего междугородний телефонный номер, естественно использовать цикл
для набора цифр. Междугородний телефонный вызов требует набора 11 цифр.
Тогда вы создаете следующий модельный цикл.
10 20 d ig it_ c o u n t = 0. d ig it jn a x = 11
20 30 d ig it_ c o u n t < = d ig it jn a x , d ig it_ c o u n t = d ig it_ c o u n t + 1
50 d ig it_ c o u n t > d ig it jn a x . выйти из цикла
30 20 набор цифры
50 продолжить дальше модель

Люди не могут и не будут вести себя структурно. Например, они могут сразу
выйти из цикла, поняв, что совершили ошибку при наборе номера.
10 20 d ig it_ c o u n t = 0. d ig it jn a x = 11
20 30 d ig it_ c o u n t < = d ig it jn a x . d ig it_ c o u n t = d ig it_ c o u n t + 1
50 d ig it_ c o u n t > d ig it jn a x . выйти из цикла
30 40 набор цифры
40 20 цифра набрана успешно
10 цифра не набрана, трубка вешается и номер набирается заново
50 продолжить дальше модель

Если скверная структура цикла должным образом моделирует ситуацию, то­


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

4.4. Методы
4.4.1. Критические тестовые значения
Рассмотрим общую детерминированную модель цикла.
10 20 lo o p _ co n tro l = s t a r t v a l . ite rm ax = upperval
20 30 lo o p _ c o n tro l > iterm ax
40 lo o p _ co n tro l < - iterm ax
30 20 lo o p p ro ce ss. lo o p _ co n tro l = lo o p _ co n tro l + in c re v a l
40 продолжить оставшуюся часть модели

Этот цикл определяется тремя значениями:


startval —начальное значение переменной управления циклом.
upperval —конечное значение переменной управления циклом.
4.4. Методы 105

increval —величина, на которую переменная управления циклом будет возрас­


тать при каждом прохождении цикла.
Критические тестовые значения — комбинация величин этих трех чисел, ко­
торые, как показывает опыт, особенно часто вызывают ошибки, плюс, в добавле­
ние к ним, нормальный или типичный вариант. Мы приводим тестовые варианты
в самом общем виде. Специфические особенности для разных типов циклов будут
обсуждаться в последующих разделах.
Обход. Любой набор величин, вызывающий немедленный выход из цикла.
Один проход. Величины, приводящие к тому, что цикл выполняется ровно
один раз.
Два прохода. Величины, приводящие к тому, что цикл выполняется ровно
два раза.
Типичное число проходов. Типичное число итераций.
Максимум: Максимальное число разрешенных итераций.
Мах + 1. На единицу больше разрешенного максимума.
Мах - 1. На единицу меньше разрешенного максимума.
Min. Заданный минимум.
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.
Но не теряйте времени на особые значения, связанные с параметрами аппаратных
средств, такими как байт или длина слова в таком современном языке программи­
106 Глава 4 • Тестирование циклов

рования, как С —за исключением, конечно, того случая, когда вы проверяете реа­
лизацию и видите, что имеете дело с низкоуровневым программированием.

4.4.2. Детерминированные циклы


Мы обрабатываем выплату жалования. Программное обеспечение должно обра­
батывать минимум одного служащего и максимум 20 000 служащих. Используя
рассмотренные выше установки, мы сразу получим следующие тестовые вари­
анты:
Обход. Нет служащих.
Один проход. Один служащий.
Два прохода. Два служащих.
Типичное число проходов. 700 служащих.
Максимум. 20 000 служащих.
Мах + 7. 20 001 служащий.
Мах - 7. 19 999 служащих.
Min. Один служащий (избыточный вариант).
Min - 1. Нет служащих (избыточный вариант).
Ноль. Нет служащих (избыточный вариант).
Отрицательное число проходов. Отрицательное число служащих?
Некоторые из этих вариантов заслуживают более подробного обсуждения.
Обход: нет служащих. Согласно требованиям, программное обеспечение не
предполагает обработку этого случая. Но что оно сделает? Может ли этот вариант,
хотя он и не имеет смысла, возникнуть? Скажем, пакет программ используется
для создания платежных ведомостей для многих разных организаций. Он обра­
батывает их по очереди (вложенный цикл с внутренним циклом для служащих и
внешним циклом для организаций). Новый клиент добавляется в очередь для об­
работки недельной платежной ведомости, но мы пока что не получили данных со­
трудников. Мы не ждем, что программное обеспечение «обработает» заработную
плату для сотрудников-фантомов. И наоборот, мы не ждем, что программа начнет
печатать бесконечное число чеков по $0.00 для имя. фамилия.
Мы тестируем. Нам платят не за привлекательность, не за справедливость
и даже не за благоразумие. Если вообще возможно смоделировать ситуацию, мы
должны сделать это и ожидать от программного обеспечения, что оно поведет себя
разумно, например, скажет нам, что «названиеорганизации не будет обработано».
При проведении тестирования мы подозреваем (и надеемся), что при обработке
платежной ведомости какой-либо другой организации не будет учтен один из слу­
жащих или ведомость будет целиком пропущена.
Один проход: один служащий. Ищем пустой дополнительный платежный чек,
продублированный платежный чек или недостаток одного чека для следующей
организации.
Два прохода: два служащих. Часто действенно, в особенности для «смешанных»
циклов. Ищите дублированную инициализацию циклов, потерю второго служа­
щего, два платежных чека для второго служащего или какую-нибудь ошибку для
следующей организации.
4.4. Методы 107

Типичное число проходов. Неперспективно для обнаружения ошибок, но если


вы это не проделаете, то, конечно, ваше тестирование может быть подвергну­
то критике. Несмотря на то, что это редко бывает эффективно для обнаружения
ошибок, это политически мудро.
Максимум. Все тестовые варианты, которые ориентированы на максимумы, мо­
гут потребовать больших затрат, в особенности для вложенных циклов. Например,
20 000 служащих и 1000 организаций означают 20 000 000 платежных чеков.
Даже с компьютерами это накладно. Дело не в том, что числа 20 000 и 1000 —это
какие-то особенные числа, вызывающие ошибки. Дело в том, что достигнуты мак­
симумы, вне зависимости от их значений. Если программисты предвидят возмож­
ные проблемы с тестированием, они встроят возможность изменить эти макси­
мальные значения для тестирования, которое в большинстве случаев может быть
проведено для 20 сотрудников и 10 организаций. Если возможность тестирования
не была целью проектирования, у вас нет другого выбора, кроме как протестиро­
вать эти экстремальные значения, по крайней мере, один раз. Но проделайте это,
скажем, для 20 000 служащих и только одной организации, и 1000 организаций, в
каждой из которой всего несколько служащих.
Максимум плюс 1. Ситуация, аналогичная случаю обхода. Мы не ждем, что
программа обработает больше, чем заданный максимум, но поскольку такая си­
туация может случайно возникнуть, мы хотим быть уверены, что это не приве­
дет к сбою и файлы не будут повреждены. Ищите ситуацию, когда в компании
X работает 20 001 служащий, в порядке обработки компания Y следует за ком­
панией X и первый служащий в компании Y получает платежный чек со счета
компании X.
Отрицательное число проходов. Если число служащих может быть введено
с клавиатуры, скажем, для того, чтобы начать обработку, тогда этот случай мо­
жет быть потенциально продуктивным. Если вы можете всеми правдами или
неправдами реализовать этот случай, попробуйте это сделать, и посмотрите, от­
клонит ли программа такое входное значение. Не обманывайте себя тем, что
этот случай действительно будет отклонен только потому, что вам так сказали.
Например, из-за ошибки ввода заявлено, что в компании X работает —10 слу­
жащих. Даже если этот случай, как и ожидалось, будет отклонен, то первые 10
платежных чеков для следующей в очереди организации Y могут быть не обра­
ботаны. Мы имеем дело с ошибками, которые ведут к произвольному или бес­
смысленному поведению. Таким образом, всегда, когда это возможно, имеет
смысл использовать произвольные и бессмысленные тестовые варианты.

4.4.3. Недетерминированные циклы


Мы ищем в файле неизвестной длины специфическую запись, которая может на­
ходиться в любом месте файла или, если уж на то пошло, может вообще не содер­
жаться в файле. Здесь мы имеем две проблемы: с размером файла и с тем местом
в файле, где может быть найдена искомая запись. Два предиката управляют по­
ведением этого цикла: предикат, управляющий получением и проверкой следую­
щей записи, и предикат, вызывающий остановку выполнения цикла в случае, ког­
108 Глава 4 • Тестирование циклов

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


вопрос о месте в файле, где найдена запись.
Обход. Файл без записей. Этот вариант также является нулевым. Поскольку
в файле нет записей, искомая запись не может быть найдена.
Один проход. Файл с одной записью.
1. Информация найдена: искомая запись и есть первая запись.
2. Информация не найдена: искомой записи нет в файле.
Два прохода. Файл с двумя записями.
3. Информация найдена в первой записи.
4. Информация найдена во второй записи.
5. Информация не найдена.
Типичное число проходов. Файл с 10 записями1.
Информация найдена в первой записи.
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 — это первое действительно хорошее типичное значение.
4.4. Методы 109

Вот мои аргументы в пользу тестового варианта МАХ + 1. Мы не предполагали,


что программное обеспечение будет обрабатывать файлы, в которых более 51 за­
писи. Если цикл действительно недетерминированный, тогда этот факт неизвес­
тен нам до того, как процесс закончится. То есть длина файла становится извест­
на только после обнаружения записи КФ (конец файла). Если это действительно
так, тогда не существует способа запретить обработку файла с 51 записью. В про­
тивном случае, если чрезмерно длинный файл отвергается до того, как начнется
обработка, тогда длина файла должна быть известна и цикл поиска не является
по-настоящему недетерминированным. Неизвестна только точка, в которой про­
цесс выйдет из цикла. Как много рассмотренных вариантов вы испробуете, зави­
сит от того, что делает цикл недетерминированным.
1. Величина максимума неизвестна и не может быть найдена. В этом случае
ничего не препятствует достижению максимального значения и вам обяза­
тельно следует попробовать МАХ + 1.
2. Досрочное прекращение. У нас есть однозначно детерминированный цикл,
выполнение которого может быть досрочно прервано (например, операто­
ром BREAKв языке С), но где это произойдет, неизвестно. МАХ + 1 не имеет
смысла, но непременно попробуйте найти искомые данные в последней за­
писи.
3. Обработка переменной управления. Это может происходить с детермини­
рованными и недетерминированными циклами. Скажем, число записей
было известно, и то, что мы хотели проделать, — это выборочная провер­
ка одной из десяти записей, вместо того чтобы проверять каждую запись в
файле. Это может быть реализовано увеличением переменной управления
цикла на 10, но это приводит к выходу величины указателя за границу фай­
ла. Тогда нам, безусловно, следует попробовать варианты МАХ + 1.

4.4.4. Вложенные циклы


Вложенные циклы сначала должны быть протестированы как индивидуальные
циклы. Задайте для внутреннего цикла типичное значение и протестируйте внеш­
ний цикл для случаев критических значений. Затем измените процедуру на про­
тивоположную, задайте для внешнего цикла типичное значение и прогоните внут­
ренний цикл через критические тестовые варианты. Эти тесты должны выявить
большинство ошибок, обычно попадающихся в одиночных, невложенных циклах.
Проблема с вложенными циклами возникает, когда два или более вложенных
цикла достигают критических значений одновременно —например, нулевых, мак­
симальных, и так далее. Вы проектируете тестовые варианты путем перебора ком­
бинаций критических значений. Это должно привести к 64 или большему числу
тестовых вариантов, если вы строго следуете этому правилу. Отступите немного
от этого и протестируйте по крайней мере комбинации обход/ноль, один, два и
МАХ для внутреннего цикла и обход/ноль, один, два и МАХ для внешнего цик­
ла. Это будет 16 случаев в дополнение к тестированию одиночных циклов — все­
го 32 теста.
110 Глава 4 • Тестирование циклов

4.5. Рассмотрение приложения


4.5.1. Индикаторы приложений
Каждый повторяющийся (циклический) процесс требует тестирования. Каждый
граф с циклами должен быть протестирован, с возможным исключением графов
для автоматов с конечным числом состояний1 (глава 9), потому что в этом слу­
чае имеется слишком много циклов, и тестирования доменов (глава 7), где присут­
ствие циклов делает метод неприменимым.

4.5.2. Предположения об ошибках


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

4.5.3. Ограничения и предостережения


Ошибки циклов обычно обнаруживаются в низкоуровневом программном обес­
печении и чаще всего имеют ограниченное влияние. Симптомы, как правило, вы­
являются неподалеку от самой ошибки и одновременно с ней. Многие из этих
ошибок будут обнаружены операционной системой или исполняемой резидент­
ной частью компилятора, потому что они вызывают переполнение памяти, обна-
ружимые ошибки указателя, чтение вне пределов файла и другую подобную че­
пуху. Ошибки, обнаруженные путем тестирования цикла, не очень коварны и мы
хотели бы надеяться, что программисты найдут и исправят их при низкоуровне­
вом тестировании модулей, где они часто могут быть найдены при тестировании
цикла. Не ожидайте очень многого от тестирования цикла для развитого программ­
ного обеспечения.

4.5.4. Автоматизация и инструментальные средства


Специальные инструменты на самом деле не нужны. Если вы используете тести­
рование циклов как часть системного поведенческого тестирования, вы можете с
успехом эксплуатировать систему покрытия/воспроизведения. Индивидуальные
тесты циклов, особенно если они касаются файлов и вложенных циклов, могут
быть трудны для реализации. Однажды реализовав и отладив типичный тесто­
вый вариант для цикла, редактируйте его, изменяя входные значения для созда­
ния других вариантов тестирования цикла, в особенности это касается комбини­
рованных вариантов, необходимых для вложенных циклов.

На самом деле любых сильно связных графов.


4.7. Вопросы для самопроверки 111

4.6. Резюме
Тестирование цикла —это эвристический метод, основанный на опыте, который
программисты приобретают, сталкиваясь с ошибками в начале и конце циклов.
Несмотря на то, что для пояснений в этой главе были использованы примеры с по­
током управления, метод эффективен для большинства графовых моделей, име­
ющих циклы (исключая сильно связные графы). Необходимые для тестирования
значения основаны на числе повторений цикла: 0,1, 2, MIN - 1, MIN, MIN + 1, ти­
пичное количество проходов, МАХ - 1, МАХ, и МАХ + 1, а также на комбинациях
этих величин для вложенных циклов.

4.7. Вопросы для самопроверки


1. Дать определение следующих терминов: критические тестовые значения
цикла, детерминированный цикл, ужасный цикл, число итераций цикла,
цикл, обход цикла, узел управления циклом, предикат управления циклом,
переменная управления циклом, узел входа в цикл, узел выхода из цикла,
цикл со смешанной проверкой, вложенные циклы, недетерминированные
циклы, цикл с проверкой до, цикл с проверкой после.
2. Рассмотрите шесть комбинаций циклов (детерминированных, недетерми­
нированных) и (с проверкой до, после, со смешанной проверкой) в языке С.
Придумайте примеры для каждой комбинации, используя следующие конс­
трукции для создания циклов: WHILE, FOR, DO-WHILE, IF/GOTO. Если комбинация
невозможна, докажите это.
3. То же, что и задание 2, но для Паскаля, с использованием F0R-T0-D0WNT0, FOR­
DO, REPEAT-UNTIL, WHILE, и всех прочих способов создания циклов.
4. В большинстве пакетов программ для подготовки налоговых документов
имеется команда для вывода форм и бланков пользователя на печать. Если
каждая форма рассматривается как объект, который следует распечатать,
этот циклический процесс детерминированный или недетерминирован­
ный? Обоснуйте ваш ответ. Если вы скажете ««детерминированный»», по­
чему практичный человек может решить запрограммировать этот процесс
с помощью недетерминированного цикла? Разработайте набор тестов для
печати действующей декларации о доходах в вашей программе подготовки
налоговых документов.
5. Классифицируйте как детерминированные или недетерминированные (по
отношению к числу итераций цикла) следующие процессы: (а) проверка ор­
фографии, (б) решение системы уравнений, (в) сортировка, (г) объединение,
(д) сложение двух чисел, (е) извлечение квадратного корня, (ж) деление
столбиком, (з) проведение переписи населения в Америке, (и) копирование
файла, (к) копирование каталога, (л) копирование всего диска, (м) проверка
диска на наличие ошибок, (н) загрузка файла, (о) подсчет числа пред­
метов в коробке, (п) пересчет числа предметов в коробке, (р) проверка
112 Глава 4 • Тестирование циклов

ваших счетов, в предположении, что ни вы, ни банк не делали ошибок,


(с) поэлементное умножение двух массивов, (т) поэлементное умножение
двух матриц, (у) извлечение квадратного корня из 16-битного числа и обес­
печение представления результата в виде 16-би гного числа, (ф) вычисление
х2hsin- 1ABS((J 2 (ABS( 17
J
f e Xdx)))) , где x — 16-битное число и pe-
0
зультат необходимо представить в виде 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,
указатель, обработка, программа, программист, программирование, язык про­
граммирования, псевдокод, ОЗУ, запись, переименовывать, повторно использу­
емый, время выполнения, поиск, упорядочение, совместно используемые данные,
побочный эффект, программное обеспечение, сортировать, исходный код, элек­
тронная таблица, оператор, хранить, структурный, символьный, синхронизация,
114 Глава 5 • Тестирование потоков данных

таблица, тестируемость, тестировщик, передавать, истинное значение, значение,


переменная.
Внутренние термины: поведенческое тестирование, слепота, тестирование вет­
вей, случайная корректность, компонент, составной предикат, поток управления,
граф потока управления, оборванная связь, детерминированный цикл, грязный
тест, входной узел, выходной узел, модель с конечным числом состояний, граф,
начальное состояние, входящая связь, интеграция, ввод, входной узел, покрытие
связей, представление графа в виде списка связей, вес связи, цикл, тестирование
цикла, модель, отрицательный тест, вложенный цикл, узел, покрытие узлов, вес
узла, недетерминированный цикл, объект, оракул, итог, исходящая связь, узел вы­
хода, путь, позитивный тест, предикат, интерпретация предиката, отношение, тре­
бование, активизировать, простой предикат, спецификация, состояние, граф по­
тока транзакций.
Определение (объекта). Объект определяется в тех случаях, когда ему присваи­
вается новое значение, он инициализируется, создается или конкретизируется. Не
путайте имя объекта или адрес ячейки памяти, использующейся для хранения его
значения, с различными возможными определениями этого объекта. Например,
ячейка памяти XYZ используется для хранения переменной с именем SAM. SAM
может принять несколько различных значений по ходу вычисления. Каждое из
этих значений является определением SAM.
Перегрузка. Имя переменной перегружено, если оно используется для обоз­
начения различных определений переменной по ходу выполнения программы.
В программировании считается, что выгода использования перегрузки заключа­
ется в экономии памяти1, но в моделях тестирования перегрузка не дает никаких
преимуществ, поскольку она только запутывает и ничего не экономит.
Логический оператор. Оператор языка программирования, включающий пре­
дикат, вычисляемый по ходу выполнения. Если предикат получает истинное зна­
чение, обработка продолжается. Если предикат получает ложное значение, проис­
ходит по крайней мере одно из следующего: управление передается обработчику
логического выражения, выражение помечается как невыполненное, выполнение
программы приостанавливается, управление передается отладочной программе.
Логические выражения обычно проверяют соотношения между значениями пере­
менных, такие как х > 17 или х + у = z. Выражения —мощный подсобный инстру­
мент тестирования. В этой главе логические выражения в основном используются
для проверки результатов вычислений.
Использование для вычислений. Объект используется для вычислений [RAPP82],
когда он применяется для расчета значения другого объекта. Например, в вы­
ражении Y : = X + Z X h Z используются для вычисления Y, a Y— определяется.
Аналогично, вХ: = X + Y, Xh Yиспользуются для вычислений, и в то же время
X (пере)определяется (здесь X—перегружено).

1 На самом деле при использовании оптимизирующего компилятора перегрузка не экономит па­


мять. Она, наоборот, по всей вероятности, увеличивает расход памяти и время выполнения, поскольку
ограничивает свободу оптимизации и увеличивает время жизни переменных, таким образом уменьшая
возможность выполнения на основе регистров. Так как время хранения переменной в памяти увеличи­
вается, то одновременно с ростом времени выполнения увеличивается загрузка RAM.
5.2. Основные термины 115

Использование в предикате. Объект используется в предикате [RAPP82],


если он применяется в предикате. В выражении IF X = Y + Z... переменные X, Y и
Z использованы в предикате. В некоторых языках (например, С) объект может ис­
пользоваться для вычисления и в предикате одновременно, поскольку вычисление
может быть встроено в предикат. Создание моделей с одновременным использова­
нием в предикате и для вычисления при тестировании поведения не дает никаких
преимуществ, если только вы не ставите себе цель внести путаницу. Предикаты
внутри утверждений не являются примерами использований в предикатах, так как
утверждения обычно не влияют на ход выполнения или на конечные значения.
Использование. Объект используется, если он задействован в предикатах и /
или в вычислениях.
Входной узел. Входной узел графа потока данных, через который вводятся дан­
ные. Имя входящего в этот узел объекта обычно написано в самом узле или прямо
перед узлом, но, если это особо оговорено, может быть написано над исходящей
из узла связью. Примеры эквивалентных обозначений входных узлов приведены
на рисунке.
[ ^Сэм, Джо^

Сэм,
Джо

Константы. Константы следует рассматривать как вводы и моделировать как


входные узлы. Множество ошибок происходит из-за использования неправиль­
ной константы, неправильного значения константы, или изменения значения кон­
станты во время вычислений. Константы уязвимы для ошибок точно так же как и
другие переменные и поэтому должны рассматриваться таким же образом.
Узел вывода. Выходной узел диаграммы потока данных —это узел, через кото­
рый выводятся данные. Имя объекта, значение которого выводится, указано ря­
дом с узлом.
Сэм, Джо ( А

Сэм,
Джо

Запоминающий узел. Пара узлов для одного и того же объекта данных. Узел

на диске). Узел ВЫБОРКАопределяет значение переменной в памяти. Верхнее обоз­


начение на рисунке показывает, как это обычно изображается в графах потока
116 Глава 5 • Тестирование потоков данных

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


узлы часто сбивают с толку, поскольку при последующей обработке не сразу может
быть понятно, какое именно значение переменной используется: значение, сохра­
ненное на диске, или значение в ОЗУ, предшествующее сохранению. Например,
при использовании в сетях с файлами совместного доступа они могут отличать­
ся (и таким образом быть источником ошибок). Использование двух различных
имен, скажем, значение_озу и значение_диск может помочь прояснить ситуацию.

Обрабатывающий узел. Узел с одной или более входящими связями и по край­


ней мере, с одной исходящей связью. Входящие связи обозначают объекты дан­
ных. Исходящая связь обозначает вычисленную функцию этих объектов данных.
На рисунке общий доход —это функция трех входящих связей —wages (заработная_
плата), taxabl e_i nterest (налогооблагаемые_проценты) и taxexempt (доход_осво-
божденный_от_уплаты_налогов). Для ясности вы можете пометить обрабатыва­
ющий узел вычисляемой функцией.
5.2. Основные термины 117

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


в которых эти значения вычисляются (то есть обрабатывающими узлами). В упро­
щенных графах потока данных, используемых в данной книге, все исходящие из
узла связи имеют одинаковые значения объектов данных. При обычном применении
графов потока данных узел может быть использован для представления нескольких
различных вычислений и, таким образом, может иметь несколько различных объ­
ектов, ассоциированных с исходящими связями. Обычная практика —размещение
имен объектов на исходящих из таких узлов связях. При таком использовании мы
неформально называем эти имена значениями исходящих связей. Подобным же об­
разом, поскольку исходящие из одного узла связи являются входящими по отноше­
нию к следующему узлу, они называются значениями входящих связей.
Предикат выбора данных. Предикат, значение которого (например, истин­
ное значение) используется для выбора одного из нескольких объектов данных.
Например, указатель на массив выбирает объект данных в массиве, на который
указывает указатель. Узел выбора данных всегда имеет предикат выбора данных.
Узел выбора данных. Узел, чьи входящие связи управляются предикатом выбо­
ра данных. Его значение (истинности или указатель) выбирает объект данных, со­
ответствующий входящей связи. На рисунке предикат выбора данных, связанный
с узлом выбора данных, выбрал объект данных VIV. Узел выбора данных вычис­
ляет специальную функцию выбора значения входящей связи для использования
в исходящей связи. Входящие связи узла выбора данных могут быть помечены
условием предиката, при котором выбирается данная входящая связь.

Управляющая входящая связь. Узел выбора данных может иметь входящую


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

\
SAM

VIV
118 Глава 5 • Тестирование потоков данных

В предыдущем примере выбор VIV мог быть основан на значениях всех входя­
щих связей:
Значение_исходящей_связи: = МАКСИМУМ (значения_входящих_связей)

В этом случае управляющей входящей связи нет. И наоборот, выбор мог быть
основан на значении управляющей входящей связи, которое определяет, какое
значение и какой входящей связи должно быть использовано:
Значение_исходящей_связи: = ВЫБОР(УПРАВЛЯЮЩАЯ_ПЕРЕМЕННАЯ. значения_входящих_связей)

В последнем примере переменная управляющей входящей связи УПРАВЛЯЮЩАЯ_


ПЕРЕМЕННАЯ выбирает одно из значений входящих связей, как, например, в случае
указателя на массив.
Граф потока данных. Граф, состоящий из входных узлов, узлов вывода, запо­
минающих узлов, узлов выбора данных и соответствующих связей и свойств.

5.3. Отношения и модель


5.3.1. Основы
Объекты (узлы): Вычисляемая функция входящих связей:
7: wages (заработная_плата)
8а: ta x a b le _ in te re s t_ in c o m e ( налогооблагаемый_доход_с_процентов)
8b: tax_exem pt_interest_incom e ( проценты_освобожденные_от_налога)
9: dividencM ncom e (доход_от_дивидендов)
10: ta x a b le _ re fu n d s (облагаемые_налогом_платежи_по_долгам)
11: a lim o n y _ rece ive d (полученные_алименты)
12: b usiness_incom e_or_loss
(доход_или_потери_в_результате_предпринимательской_деятельности)

21: other_incom e (другие_доходы)


22: общий_доход : = заработная_плата + налогооблагаемый_доход_с_процентов +
... + другие_доходы.

Обратимся к форме 1040. Узлы с 7 по 21 —источники данных. Из них узлы 8а,


9, 10, 12, 13, 14, 15, 18, 19 и 21, возможно, пришли из других форм ВНС, но будут
трактоваться здесь как входные данные, чтобы не усложнять пример. Строка 22 —
обрабатывающий узел. Узел 22 также зависит от узлов 15Ь и 16Ь, расчетом кото­
рых мы на данный момент пренебрегаем (а вы не должны). Почти каждая строка
в форме 1040 соответствует объекту данных, который вводился без предваритель­
ного расчета, пришел из другой формы или был рассчитан по ходу обработки фор­
мы 1040.
Отношение {связи). Непосредственно используется для расчета значения.
В последнем примере узлы с 7: wages (заработная_плата) по 21: otherincome (дру-
гие_доходы), исключая 15а: IRA (индивидуальные_пенсионные_счета (ИПС)) и
16а: pensions (пенсии), напрямую используются для вычисления значения узла
22: total income (общий_доход). Эти значения также используются косвенным
образом для вычисления значений других объектов — таких как узел 53: уоиг_
total_taxes (общая_сумма_ваших_налогов), но поскольку применение не являет­
5.3. Отношения и модель 119

ся прямым, то здесь нет прямых стрелок из этих узлов к узлу 53. Однако есть по­
токи данных из некоторых из этих узлов, приходящие в узел 53.

Свойства узлов (веса узлов). Пометьте узлы функцией входящих связей, кото­
рую они вычисляют. Это может быть просто имя выхода функции (например, об-
щий доход) или сама фактическая функция, например, формула.
Свойства связей (веса связей). Добавление весов связей не является необхо­
димым, поскольку эта информация заложена в весах узлов. Однако поскольку
графы потока данных могут быть довольно сложными, обычно исходящие связи
помечаются именами представляемых ими объектов данных. Если узел представ­
ляет собой узел выбора данных, пометьте входящие связи значениями предиката
выбора, соотнесенными с каждой входящей связью.

5.3.2. Аналогии с графами потока данных


В графах потока управления имеются конструкции, эквивалентные конструкци­
ям в графах потока данных.
Простая обработка. Обычно простая обработка обозначается одиночным уз­
лом обработки без принятия во внимание порядка обработки. Несмотря на то,
что предыдущий пример для вычисления total_income (общий_доход) выглядит
упорядоченным, этого упорядочения не требуется, поскольку ВНС не настаива­
ет, чтобы мы заполняли налоговые документы, сначала указывая сумму заработ­
ка, затем налог на проценты, и так далее. Если мы пишем программу на обычном
120 Глава 5 • Тестирование потоков данных

языке программирования, тогда нам следует выбрать определенный порядок вы­


полнения действий, но это упорядочение делается по нашему выбору и не сущес­
твенно для решения задачи. В диаграммах потока данных мы не навязываем опре­
деленную последовательность, не предполагаемую требованиями.
Обозначение в виде списка связей удобнее графического представления.
Комментарий, относящийся к связи, согласно нашей договоренности соответ­
ствует первому узлу из пары. Это облегчит нам задачу, поскольку нам не придется
писать список узлов и затем еще и список связей. В следующем примере коммен­
тарий other_i ncome (другие_доходы) соответствует связям, исходящим из узла 21.
21: 22:
other_incom e (другие_доходы)
11: 22:
a lim o n y _ rece ive d (полученные_алименты)
15a: 15b:
t o t a l_ I R S _ d is t r ib u t io n (общее_распределение_ИПС)
15b: 22:
ta x a b le amount (налогооблагаемая_сумма) (справьтесь у вашего
бухгалтера)
16а: 16b: ta x a b le amount (налогооблагаемая_сумма) (справьтесь у другого
вашего бухгалтера)
17: 22: r e n t a l_ r o y a lt ie s ( доходы_от_аренды)
18: 22: farm _incom e_or_loss (прибыль_или_убыток_от_сельского_хозяйства)
19: 22: unemployment_compensation (пособие_по_безработице)
20а: 20b: s o c ia l_ s e c u r it y _ b e n e f it (пособие_по_социальному_обеспечению)
20Ь: 22: t a x a b le _ s o c ia l_ s e c u r it y _ b e n e fit (налогооблагаемые
пособия_по_социальному_обеспечению)
8b: tax_exem pt_i n te re s t_ i ncome ( проценты_освобожденные_от_налогов)
9: 22: dividend_incom e (доход_от_дивидендов)
14: 22: другие_прибыли_и_убытки_из_формы_4797
10: 22: ta x a b le _ re fu n d s (облагаемые_налогом_платежи_по_долгам)
8a: 22: ta x a b le _ in te r e s t (налогооблагаемые_проценты)
12: 22: business_incom e_or_loss
( прибыль_или_убытки_от_предпринимательской_деятельности)
7: 22: wages (заработная_плата)
13: 22: c a p ita l_ g a in s _ o r_ lo s s (капитальная_прибыль_или_убытки)
22: to ta l_ in co m e (общий_доход): = wages (заработная_плата) +
ta x a b le _ in te re s t_ in c o m e (налогооблагаемый_доход_с_процентов) +
tax_exem pt_interest_incom e (проценты_освобожденные_от_налога) + ... +
other_incom e ( другие_доходы)

He так важно, как мы переставим строки в вышеприведенном графе. Связи опре­


делены, так что порядок, в котором мы расположим их на странице, не влияет на об­
работку или на модель. Я включил узел 8Ь, который, как кажется, никуда не ведет;
ВНС желает получить эту информацию, несмотря даже на то, что она не использует­
ся в этом расчете. По-видимому, они используют ее для каких-то других расчетов.
IF-THEN-ELSE. Здесь приведена спецификация для строки 36 из формы 1040
ВНС.
36 Если значение в строке 32 (Adjusted_Gross_Incom e (скорректированный_общий_доход))
меньше или равно $83.850. умножить $2450 на общее число льгот, заявленных в строке 6е.
Если сумма в строке 32 (Adjusted_Gross_Incom e (скорректированный_общий_доход)) больше
$83,850. смотрите инструкции (ВНС 1040) для того чтобы рассчитать облагаемую сумму.

Приводим модель псевдокода для этой операции.


36.1: 36: I F ( ( СОД) строка_32 <= $ 83850) THEN строка_36: = число_ освобождений *
$2450 ELSE строка_36: = расчет_согласно_инструкции.
5.3. Отношения и модель 121

Ниже приводится классический граф потока управления для этой операции.


36.1: 36.2: узел предиката. СОД <= $83850
36.1: 36.3: узел предиката. СОД > $83850
36.2: 36: Строка_36: = число_ освобождений * $2450
36.3: 36: Строка_36: = расчет_согласно_инструкции

Переменная Строка_36 не перегружена. Почему? Вот граф потока данных для


этой операции.
6е: 36.1: общее_число_ освобождений
k l: 36.1: значение_константы_$2450
к2: 36: значение_константы_$83850
36.1: 36: общее_число_освобождений * k l
32: 36: adjusted_gross_incom e (скорректированный_общий_доход)
Р23: 36: расчет_согласно_инструкции
36: узел_выбора_данных 36.1 IF СОД <= к2
Р23 IF СОД > к2

Меня не удовлетворяет эта модель, поскольку средства управления перемеша­


ны с вычислением. Действительно, замысловатая модель, могла бы запутать, так
что я бы добавил несколько связей, чтобы сделать ситуацию более ясной, предло­
жив следующий граф потока данных.
6е: 36.1: total_num ber_of_exem ptions (общее_число_освобождений)
к Г. 36.1: значение_константы_$2450
36.1: 36: total_num ber_of_exem ptions (общее_число_освобождений) * k l
Р23: 36: расчет_согласно_инструкции
к2: 36.2: значение_константы_$83850
32: 36.2: adjusted_gross_incom e (скорректированный_общий_доход)
36.2: 36: значение_селектора (управляющая входящая связь)
36: ... узел_выбора_данных 36.1 IF СОД <= к2 (значение_селектора =
ИСТИНА)
Р23 IF СОД > к2 (значение_селектора = ЛОЖЬ)

Вы, возможно, захотите начертить все эти графы потока данных для сравнения.
Модели потоков данных могут показаться более сложными по сравнению с ранее
рассматриваемыми моделями, но это не так. Они только включают больше инфор­
мации, чем обычно закладывается в модель потока управления. Дополнительные
детали возникают вследствие того, что каждый объект данных должен откуда-то
появиться. Вот почему мы добавили два узла kl и k2, отвечающие за константы
$2450 и $83850 соответственно. Мы добавили связь 32 : 36 в первую модель пото­
ка данных (связь 32 : 36.2 во вторую модель потока данных) потому что adjusted_
gross_income (скорректированный общий доход) должен откуда-то появиться.
Связь 6е: 36.1 для переменной total_number_of_exemptions (общее_число_освобож-
дений) была добавлена по той же причине. Если мы уберем эту дополнительную
информацию (уменьшив детализацию нашей модели), мы получим даже еще бо­
лее простую модель (по числу узлов и связей), чем модель потока управления.
36.1: 36: total_num ber_of_exem ptions (общее_число_освобождений) * k l
Р23: 36: расчет_согласно_инструкции
36: ... узел_выбора_данных 36.1 IF СОД <= к2
Р23 IF СОД > к2
122 Глава 5 • Тестирование потоков данных

При качественном проектировании программных средств предполагается, что


значения константам kl и к2 присвоены раньше в программе или хранятся в таб­
лице. Это намного лучше, чем многократное повторение значений $2450 и $83850
в коде программы. Это правильный подход, поскольку уменьшается вероятность
ошибок, при которых якобы постоянные величины в разных местах отличают­
ся друг от друга. Это хорошо также для сопровождения, поскольку в том случае,
когда ВНС изменит ставки налогового обложения (что неминуемо когда-нибудь
случится), нужно будет изменить одно значение в одном месте1. Это, конечно, пра­
вильный подход, но мы не можем быть уверены, что программист так и поступил.
Но почему об этом должен заботиться тестировщик? Используя символьные кон­
станты в нашей модели, мы уменьшаем вероятность ошибок там, где мы непредна­
меренно используем несколько различных значений предполагаемой константы.
Хороший дизайн программного обеспечения часто также хорош и для проектиро­
вания теста.
IF-THEN. Мне не нравятся конструкции типа IF-THEN в графах потока данных,
поскольку они неоднозначны, если условие не выполняется. В графах потока уп­
равления неоднозначности меньше, поскольку следующий оператор всегда подра­
зумевается. Большинство конструкций IF-THEN лучше моделировать при помощи
конструкций IF-THEN-ELSE, как в следующем примере:
IF (предикат - ИСТИНА) then х: = функция ELSE х: = пусто

Явно определяйте, что происходит с объектом данных, когда предикат не исти­


нен. Например, постулат:
54: Удержан федеральный налог. Если вы используете форму 1099. отметьте [ГРАФА]

можно представить при помощи следующего псевдокода и модели потока данных,


соответственно.
54: I f из_форм(ы)_1099 THEN графа: = отмечена ELSE графа: =
не_отмечена
54 .Г . 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 году. Однако, в отличие от вас, я не мог использовать символьную переменную для этих
чисел. Было бы намного проще, если бы я мог так поступить. Если я пропустил несколько обновлений,
я уверен, что вы сообщите мне об этом, — но надеюсь, что вы простите меня.
5.3. Отношения и модель 123

рассчитанное где-то в другом месте графа потока данных значение для сэм. Первый
случай не представляет проблемы. Мы моделируем его так: IF х > ОTHEN сэм: = джо
ELSE сэм:= пусто. Второй случай тоже не сложен. Он должен быть смоделирован
так: IF х > О THEN сэм: = джо ELSE сэм: = старое_значение_сэм. Нам снова не нужно
сомнительное IF-THEN.
Возможно, проблема возникнет, если переменная сэм определена в более чем
одном месте. Какое значение нам следует использовать для случая ЛОЖЬ? Это —
хороший вопрос, не имеющий простого ответа. Тут возможны варианты, пос­
кольку в случае неоднозначности не бывает очевидного ответа. Конструкция
IF-THEN однозначна в графе потока управления, потому что графы потока управле­
ния имеют подразумеваемое упорядочение (упорядоченную последовательность).
Следовательно, обычно имеется подразумеваемое (предшествующее) значение
для такой ситуации. В графах потока данных, в которых нет подразумеваемого
упорядочения, значение становится неоднозначным. Вот почему следует избегать
использования IF-THEN в подобных моделях. Но заметьте, что неоднозначность
в модели увеличивает вероятность ошибок программирования.
В качестве примера использования 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 вход_статус
О.Г. графа_1: графа_1: 6: выбор: IF статус = неженат
выбрать отмечена ELSE выбрать не
отмечена
124 Глава 5 • Тестирование потоков данных

графа_2: графа_2: 6: выбор: IF статус= жен_совм


графа_3: выбрать отмечена ELSE выбрать не
отмечена
графа_4: графа 3: 6: выбор: IF статус = жен_раздельно
графа_5: выбрать отмечена ELSE выбрать не
отмечена
графа_4: 6: выбор: IF статус = домовладелец
отмечена: графа_1: выбрать отмечена ELSE выбрать не
отмечена
графа_2: выбрать отмечена ELSE выбрать не
отмечена
графа_3: графа_5: 6: выбор: IF статус = вдовец
графа_4: выбрать отмечена ELSE выбрать не
отмечена
графа_5: 6: продолжение модели
не отмечена: графа_1:
графа_2:
графа_3:
графа_4:
графа_5:

Модель может показаться сложной, но это не так, потому что определено всего
пять различных выходов (по одному на каждую графу). В тестируемом программ­
ном обеспечении, в котором реализуется этот процесс, мы должны убедиться не
только в том, что правильная графа отмечена, но и в том, что все остальные графы
остались неотмеченными и отмечено не больше одной графы. Заметьте, что если
вход статус_налогоплателыцика не является одним из пяти правильных вариан­
тов, тогда все графы останутся неотмеченными.
Селектор CASE. Структура Селектора CASE в графах потока данных —обобщение
структуры IF-THEN-ELSE. Модель потока данных для строки 34 такова:
34.1: 34: вход $3800 (холост, de du ction (возврат): =
$3800)
34.2: 34: вход $5600 (домовладелец.
de du ction (возврат): = $5600)
34.3: 34: вход $6350 (женат совместная декларация,
de du ction (возврат): = $6350)
34.4: 34: вход $6350 (вдовец.
de du ction (возврат): = $6.350)
34.5: 34: вход $3175 (женат, заполнено раздельно,
de du ction (возврат): = $3175)
статус: 34: вход статус_налогоплательщика (управляющая входящая связь для
селектора 34)
34: выбор статус_налогоплательщика: холост 34.1
домовладелец 34.2
совместно 34.3
вдовец 34.4
раздельно 34.5

Строка 34 иллюстрирует работу узла CASE. Я предпочитаю использовать пере­


менную статусналогоплателыцика для моделирования предиката выбора, потому
что это тот способ, который используется в инструкциях ВНС. Обладая инфор­
мацией, какая графа была отмечена в строках с 1-й по 5-ю, я бы создал в строках с
1-й по 5-ю модели переменную номерграфы, значение которой устанавливалось бы
5.3. Отношения и модель 125

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


ние номер_графы для управления предикатом выбора в строке 34.
Так же как и в случае конструкции IF-THEN, здесь возможна неоднозначность.
Что произойдет, если ни одна из граф (строки 1-5) не будет отмечена? Что про­
изойдет, если в строках с 1 по 5 отмечено более одной графы?

5.3.3. Короткие замечания и упрощенные методы


Не забудьте, что мы имеем дело с моделями, а не с программным обеспечением.
Следовательно, закладывайте в модель как можно больше деталей из тех, что вам
нужны, но не все, что вам известны. Ваши модели потока данных, используемые
при разработке тестов, должны иметь различные степени детализации по анало­
гии с диаграммами потока данных, используемыми в проектировании. Например,
имея дело с файлом, вы могли бы извлечь пользу от наличия нескольких уровней
детализации (и нескольких различных моделей потока данных).
Уровень файла. Рассмотрите весь файл как один объект данных, с которым об­
ращаются как с единым целым. Сконцентрируйтесь на операциях, которые при­
меняются к целому файлу, и на операциях между файлами, например, открыть,
закрыть, копировать, сравнить, переименовать, удалить, переместить, переслать,
объединить, извлечь, создать.
Уровень записи. Тесты, которые вы проделали па уровне файла (если они
успешно пройдены), гарантируют, что вы работаете с правильным файлом.
Сконцентрируйтесь на получении правильной записи в модели для уровня запи­
си. Проводимые операции аналогичны операциям на уровне файла: добавить за­
пись, удалить запись, копировать запись, найти запись, извлечь, сравнить, пере­
местить.
Уровень поля. Рассмотрите индивидуальные поля в записи. Здесь может
быть несколько уровней. Например, одно из полей может являться массивом.
Рассмотрите следующие операции: вставить поле, удалить поле, изменить значе­
ние поля, копировать значение, сосчитать число полей.
Уровень обработки. Обычно его можно совместить с уровнем поля, но это не
всегда стоит делать, если операции с полями либо обработка данных достаточно
сложны. Модель обработки сама по себе может быть создана на нескольких раз­
личных уровнях детализации.
Группы данных. В ряде случаев (требования приложения или способ про­
граммирования) вы, может быть, захотите сгруппировать те объекты данных,
которые обрабатываются схожим образом, даже если они не связаны в контек­
сте данного приложения. Это поможет вам создать многократно используемые
модели. То есть одна и та же модель может быть использована для нескольких
различных, возможно, не связанных, частей приложения. Возможность повтор­
ного использования — признак хорошего программирования и хорошего дизай­
на тестов.
Качественное проектирование программного обеспечения упрощает задачу
моделирования, поскольку разработчики создают иерархический набор потоков
данных, структура которого отражена в структуре разбиения процесса обработки.
126 Глава 5 • Тестирование потоков данных

Когда вы, как об этом говорилось выше, разделяете модель на уровни, вам, воз­
можно, придется «создать» новые объекты данных, которых нет в спецификациях.
Определите их так точно, как если бы вы занимались программированием, задай­
те их атрибуты, определения и так далее. После определения, такая псевдопере­
менная становится переменной при использовании в модели потока данных более
высокого уровня.
При создании и использовании таких упрощенных методов вы не програм­
мируете и не меняете технические требования — вы закладываете фундамент,
необходимый для создания высокочувствительного теста. Если приложение
сложно организовано, приготовьтесь к тому, что тесты будут, подобно ему, об­
ладать сложной структурой. Если программное обеспечение выигрывает при
использовании иерархической структуры, разбиения и многократно использу­
емых компонентов, то выиграет и тестовый комплект. Большинство методов,
использование которых оправдано при проектировании программы, окупаются
при разработке тестов.
Вы могли бы раскритиковать такой подход к организации разработки тестов,
сказав: «Ни приложение, ни программное обеспечение не всегда бывает струк­
турировано должным образом. Предполагая хорошую структуру тестируемой
системы при проектировании тестов, вы можете упустить из виду возможность
выявления ошибок, являющихся следствием плохой структуры, — например,
ошибок, проистекающих из смешения уровней файла, поля, записи данных с их
обработкой».
Подобный критицизм заслуживает внимания, но из того, что структура про­
граммы размыта, не следует того, что плохо структурированное тестирование бу­
дет более эффективным. Не следует доверять поимку вора вору. Необходимо ра­
ботать систематично.
Как можно повысить эффективность использования скудного времени, отпу­
щенного на проектирование тестов? Существует гораздо больше способов спроек­
тировать программное обеспечение плохо, чем способов сделать это хорошо. Если
вы решили придерживаться неструктурированного проектирования тестов в по­
пытке найти некоторые ошибки, вы можете также ошибиться в предположениях о
коде, как и при хорошо структурированном проектировании. Вы обманываете са­
мих себя. Единственный способ сделать обоснованные допущения о коде, на кото­
рых можно основать проектирование тестов, —это посмотреть на код и построить
дизайн ваших тестов в соответствии с его структурой. Но это уже нельзя назвать
тестированием черного ящика.
Приняв структурированную модель, вы увеличиваете вероятность того, что
ваши позитивные тесты будут обеспечивать покрытие требований. Такой на­
бор тестов более объективен и при создании негативных тестов. Например, раз­
деляя тесты на уровне файла и полей записи, вы можете яснее увидеть, какая
имеется возможность для грязных тестов, в которых эти уровни перемешаны.
Проектирование грязных тестов будет проще и потребует меньшего количества
предположений об ошибках, так что работу будет проще оценить.
5.3. Отношения и модель 127

5.3.4. Упорядочение, совмещение потока


управления и потока данных, циклы
5.3.4.1. Упорядочение
Ссылки на материал, описанный в этом разделе, можно встретить в [RUGG79].
Данная книга рекомендуется для дополнительного ознакомления с рассматрива­
емыми концепциями.
Граф потока данных содержит мало указаний о порядке обработки, продикто­
ванном используемыми языками программирования и аппаратным обеспечением.
Но некоторое упорядочение все же остается, и информация о некотором упорядо­
чении будет уместна. Вот четыре общих вида упорядочения, которые могут встре­
титься в графе потока данных: удобное, но не необходимое, необходимое, синхро­
низация, итерирование.
Не необходимое, но удобное. У нас есть последовательность операций, которые
рассчитывают значения вместе с промежуточными значениями. Вам необходимо
знать adjusted gross income (скорректированный_общий_доход) (строка 31), для
того чтобы рассчитать величину вашего налога. adjusted_gross_income (скоррек-
тированный_общий_доход) зависит от переменной total_income (общий_доход)
(строка 22), которая, в свою очередь, зависит от других полей. В конечном счете
эти поля зависят от входных данных. Может показаться, что подобное упорядо­
чение необходимо, но это не так. Каждая строка в налоговой декларации может
быть (теоретически) выражена прямо в виде комбинации входных данных. Так
поступить допустимо, но глупо, потому что каждая строка в налоговой форме в
этом случае была бы суммой множества вводимых полей. Такое упорядочение
удобно, но не необходимо. Если вы уберете все подобное упорядочение из типич­
ной диаграммы потока данных, вы получите только входные узлы и (очень слож­
ные) выходные узлы.
Когда вы видите граф потока данных, содержащий между узлами входа и вы­
хода еще другие узлы, проверьте эти промежуточные узлы, чтобы определить, яв­
ляются ли они необходимыми или просто удобны. Можно ли упростить или сис­
тематизировать ваш граф, удалив некоторые из этих упорядочений и выразив
выходы более явно через входные данные? Это диаметрально противоположно
тому, что вы делали, когда изучали псевдопеременные и иерархические разбие­
ния в разделе 5.3.3.
Необходимое. Иногда упорядочение необходимо. Вы не можете прочитать
(файл, до того как он создан (несмотря на то, что это хороший тест) или закрыть
неоткрытый файл. Вы должны понять, как работает приложение, чтобы узнать,
является ли упорядочение в графе потока данных необходимым или нет. Не уда­
ляйте необходимое упорядочение, потому что если вы это сделаете, вы пропустите
полезные тесты и создадите бесполезные.
Синхронизация. Если имеются параллельные процессы (например, в систе­
мах с общими данными или сетевых приложениях), тогда существует необхо­
димое упорядочение и проблема синхронизации. Например, с: = а + Ь, где
а и b берутся из разных мест. Проблема синхронизации приводит к пяти до­
полнительным тестовым вариантам, зависящим от последовательности собы­
128 Глава 5 • Тестирование потоков данных

тий (почему?), и ее мы обсудим в главе 6. Если в вашем случае таких проблем


достаточно много, может оказаться, что модель потока данных не подходит для
данного случая, и лучше рассмотреть модель потока управления или модель по­
тока транзакций.
Итерирование. Если у вас есть узлы выбора, вы можете вернуть результат вы­
числения назад, в более раннюю точку на графе потока данных и создать цикл.
Процесс повторяется до тех пор, пока (как мы надеемся) не выполнится условие
прекращения. Циклы и способы их обработки в контексте модели потока данных
обсуждаются в разделе 5.3.4.3.
5.3.4.2. Совмещение потока управления и потока данных
Модели потока управления и модели потока данных плохо сочетаются [KAVI87].
Каждая модель —это обособленная часть общей картины, сосредоточенная на од­
них аспектах проблемы и игнорирующая другие. Модель —это способ структури­
ровать наше мышление, необходимый для получения полезных тестов. Если мо­
дель чересчур сложна, это только запутает нас. Но как мы должны обрабатывать
необходимое упорядочение в рамках модели потока данных? Вот некоторые со­
ображения.
Более одной модели. Сделайте отдельно модель потока данных и модель потока
управления. Каждая приведет к различным тестам, и? как мы надеемся, при таком
подходе не будет значительного перекрытия созданных тестов. Возможно, вы пред­
почтете в качестве альтернативы модель с конечным числом состояний (глава 9).
Поместите модель потока управления внутрь модели потока данных. У вас
есть повторяющаяся процедура в модели, большей частью определяемой потока­
ми данных. Например, вы должны найти файл, чтобы получить данные, которые
затем используются в вычислении. Рассматривайте поиск файла как единичную
операцию внутри модели потока данных. Для поиска файла используйте модель
потока управления.
Поместите модель потока данных внутрь модели потока управления. Скажем,
вы проделываете повторяющуюся обработку для каждой записи файла. Обработка
моделируется при помощи графа потока данных. Расположите часть, представля­
емую потоками данных, внутри модели файла (либо модели потока управления
или модели потока транзакций). Рассматривайте файловую часть как модель по­
тока управления, а обработку как модель потока данных.
Когда вы проектируете тестовый вариант, никто не знает, как вы это делаете.
Тестовый вариант состоит из исходных условий, вводимых данных, ожидаемых
результатов. И история умалчивает (или должна умалчивать) о том, получили ли
вы эти результаты, используя модель потока управления, модель потока данных
или каким-то другим способом.
5.3.4.3. Циклы
Как бы вы ни моделировали проблему и какие бы ни были в ней циклы (необходи­
мые или нет), вам следует использовать методы тестирования циклов из главы 4.
К счастью, в потоковых моделях нам нечасто приходится иметь дело с циклами.
Мы должны различать необходимые и несущественные циклы.
5.3. Отношения и модель 129

Причиной возникновения несущественных циклов является природа языков


программирования. Если вы хотите добавить два массива, в большинстве ком­
пьютеров или языков вы, вероятно, проделаете это с помощью цикла. Цикл не
необходим, потому что на параллельном компьютере вы могли бы проделать эту
операцию параллельно. Большинство циклов, встречаемых нами в программном
обеспечении, несущественны. Большинство детерминированных циклов не явля­
ются необходимыми.
Необходимые циклы реализуют итерационные или потенциально бесконечные
процедуры. Решение уравнения с помощью итерационного процесса, такого как
итерация Ньютона—Рафсона, — хороший пример. Поиск и сортировка файлов с
неограниченной длиной —другие два примера. Большинство недетерминирован­
ных циклов являются необходимыми1*5.
Если у вас есть какие-нибудь необходимые (или удобные) не очень сложные
циклы (то есть не вложенные, без переходов в них или из них, без большого коли­
чества управляющей логики в них), тогда простой и эффективный путь рассмот­
реть проблему цикла в рамках модели потока данных —это развернуть цикл.
Рассмотрим модель, приведенную на рисунке, пренебрегая пока что различия­
ми между графами потока управления и графами потока данных. Итерационный
процесс здесь зависит от входных переменных А, В и С. В ходе этого процесса про­
исходит вычисление функции X и счетчика цикла I. Рассчитав первый результат
(X,), программа переходит к узлу ЦИКЛ, где принимается решение о том, следует ли
выйти или же продолжить. Управляющий предикат может быть функцией как X,
так и I, либо обоих параметров.

Нам необходимо знать исходное значение для X, потому что выполняемое


в узле X вычисление зависит от предыдущего значения X. Я назвал исходное

1 Мы все знаем, что подготовка наших налоговых деклараций — повторяющаяся процедура, кото­
рая производит впечатление бесконечной (до 15 апреля). Зная особенности бюрократического мыш­
ления, я очень надеялся найти много необходимых циклов в налоговых законах. Я просмотрел все
формы и инструкции (это порядка 950 страниц терминологии ВНС) в моем налоговом пакете. Я об­
наружил множество способов уйти от уплаты налогов, но не нашел ни одного необходимого цикла. Я
уверен, что они там есть, но я не эксперт по налогам, так что я не смог найти пи одного. Любой читатель,
который укажет мне на необходимые циклы, чтобы использовать их в качестве примеров в последую­
щем издании книги, получит бесплатный экземпляр этого издания.

5 Зак. 770
130 Глава 5 • Тестирование потоков данных

значение Х0. Нам также нужно исходное значение для счетчика итераций IQ. Мы
не знаем, действительно ли код содержит эти исходные значения в виде явно вы­
раженных констант, но, следуя логике, полагаем, что они существуют. Опыт гово­
рит нам, что ошибки исходных значений случаются сравнительно часто, так что
это имеет смысл проверить.
Первая модель мне не нравится. Она не настолько близка к модели потока дан­
ных, насколько мне бы хотелось. Узел ЦИКЛ имеет скрытую сложность, и наиболее
важный вопрос — каким образом выбраны исходные значения? Модель на следу­
ющем рисунке более ясна. Я добавил два узла выбора данных (помеченных «?»),
чтобы выбрать между исходными значениями X и I. Я также ввел управляющую
связь из селектора I к селектору X, чтобы показать, как программа могла бы вы­
бирать между исходным значением Х0 и последующим значением X,. Например,
там мог бы находиться предикат в форме IF I = О THEN ВЫБРАТЬ X, ELSE ВЫБРАТЬ Х0.
В случае реальной проблемы вам следовало бы иметь больше информации о спе­
цифике условий прекращения цикла и разместить больше этой информации внут­
ри чисто потоковых (по данным) узлов. Например, условие прекращения цикла
может быть основано на разнице между предыдущим и настоящим значениями
X и сравнении ее с некоторой маленькой константой £.

Я развернул цикл дважды в следующей модели. Узел производит исходное


вычисление, основанное на исходных значениях Х0 и 10. Узел Х2 вычисляет функ­
цию, основанную на константах А, В и С, и использует новые значения X и I. Из-за
инициализации функции ее значение для Х2, вероятно, не будет тем же самым, что
и для Хг Для узла Х3, который, вероятно, имеет то же значение функции, что и Х2,
цикл снова развернут.
Мы можем продолжить разворачивать цикл и получим модели для большо­
го числа повторений (и, следовательно, с многочисленными узлами и связями).
Но это не очень хорошая идея. Сколько раз нам следует разворачивать цикл?
Дважды!1 Это дает вам три модели: первая остановится в узле X,, вторая остано­

1 Мы должны развернуть один раз — чтобы удовлетворять требованиям методик структурного


тестирования, поскольку мы хотим использовать простые пути. Второй разворот оправдан опытом
и теоремой Хуанга. Смотри [BEIZ90].
5.4. Методы 131

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

При тестировании циклов в модели потока данных мы в основном занимаем­


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

5.4. Методы
5.4.1. Основы
Ссылки на материал, описанный в этом разделе, можно встретить в [SNEE86,
ZWEB92]. Данные книги рекомендуются для дополнительного ознакомления с
рассматриваемыми концепциями.
Проектирование и выполнение тестов остаются такими же, как и для моделей
потока управления, с незначительными различиями, которые вытекают из того,
что мы имеем дело с графами потока данных, а не с графами потока управления.
В дальнейшем я буду предполагать, что у нас нет циклов.
1. Проверьте спецификацию.
2. Идентифицируйте входные переменные, особенно константы. Дайте каж­
дой входной переменной имя и создайте для нее входной узел.
132 Глава 5 • Тестирование потоков данных

3. Перепишите спецификацию таким образом, чтобы каждой вычисляемой


функции соответствовало одно предложение.
4. Перечислите функции, начиная с тех, которые зависят только от входных
переменных.
5. Перечислите функции, зависящие только от входных переменных и резуль­
татов функций, перечисленных в пункте 4.
6. Продолжайте подобным образом перечислять функции, пока не охватите их
все. У вас должен получиться список, в котором наверху будут находиться
функции, зависящие только от входных переменных, а далее, по мере про­
движения вниз, будут находиться функции, зависящие от всё большего ко­
личества промежуточных вычислений. Заметьте, что, как правило, строгое
упорядочение невозможно, но это и не нужно.
7. Проверьте промежуточные функции (в том числе функции, зависящие
от входных переменных и от выходных данных других функций) и посмот­
рите, является ли упорядочение необходимым или просто удобным. Если оно
необходимо, пометьте соответствующий узел, а также узлы, которые дикту­
ют эту необходимость. Если упорядочение не обязательно, посмотрите, мож­
но ли упростить модель, удаляя промежуточные узлы и выражая функцию
непосредственно через входные переменные? Если вы можете удалить узлы
и связи без чрезмерного усложнения вычисляемой функции, сделайте это.
8. И наоборот, возможно, вы сможете упростить модель, добавляя промежу­
точный узел для сложного вычисления. Однако если вы проделаете это, вы
должны проверить, является ли ваше промежуточное вычисление верным.
Возможно, для этого придется модифицировать исходный код и добавить
оператор утверждения.
9. Теперь у вас есть набор узлов (из них каждый имеет имя) которые выража­
ют обработку простейшим для вас способом1.
10. Имеется некое вычисление или функция, связанная с каждым узлом.
Переменные в имени данной функции соответствуют узлам, с которыми
связан данный узел, то есть, связям. Теперь у вас есть модель.
11. Проверьте вашу модель. Проверьте вашу работу.
Действуйте точно так же, как в случае моделей потока управления. Здесь будут
некоторые отличия в деталях, которые мы рассмотрим в дальнейших разделах. Но
для начала нам потребуются определения.
Подграф. Часть графа, которая соответствует правилам построения графов то
есть имеющая узлы входа и выхода, не имеет оборванных связей, не имеет изоли­
рованных узлов, и так далее.

1 То, что обязательно для вас, совсем не обязательно для меня, и наоборот. Никогда не забывайте,
что модели — это мысленные инструменты и что в них нет чего-либо принципиально правильного или
неправильного. Они могут быть только полезными или бесполезными. Вы можете предпочесть сохра­
нить несущественное промежуточное вычисление в модели, поскольку знаете, что это будет выгодно в
другом контексте или просто потому, что люди часто склонны думать подобным образом.
5.4. Методы 133

Порожденный подграф. Подграф графа, выбранный в соответствии с определен­


ным критерием так, что для данного критерия подграф обладает всеми свойства­
ми полного графа для выбранных узлов и связей [WEIS81, WEIS84]. Критериев
много, и таким образом, существует много различных порожденных подграфов.
Если, например, граф представляет собой граф потока управления и интересу­
ющий нас критерий —это поведение вдоль пути, то подграф содержит модель все­
го кода вдоль выбранного пути. Здесь мы в основном заинтересованы в порожден­
ных подграфах потоков данных.
Порожденный подграф потока данных. Порожденные подграфы потоков дан­
ных выбираются по отношению к объектам данных; в нашем случае —обычно по
отношению к выходному узлу. В общем случае, однако, порожденный подграф по­
тока данных по отношению к данному объекту (узлу) —это подграф графа пото­
ка данных, содержащий все потоки данных, которые прямо или косвенно могут
прийти в заданный узел, и все потоки данных, которые могут быть доступны из
этого узла. Если порожденный подграф (как обычно) выбирается по отношению к
выходному узлу, то в этом случае он содержит все узлы, которые могут повлиять
на значение соответствующей выходной величины.
Проще говоря, вы просто отслеживаете все входящие в интересующий вас узел
связи и помечаете их, затем помечаете все связи, входящие в те узлы, из которых
данные связи исходят, и так далее, и то же самое проделываете для исходящих
связей, вплоть до выходных узлов1.
12. Выберите «пути» тестирования. Это в действительности не пути, а порож­
денные подграфы.
13. Активизируйте порожденные подграфы.
14. Предскажите и запишите ожидаемые итоги.
15. Определите критерий соответствия для каждого из тестов.
16. Выполните тесты.
17. Подтвердите итоги (например, значения узла выхода).
18. Подтвердите значения в промежуточных узлах.

5.4.2. Иерархия покрытия2


Ссылки на материал, описанный в этом разделе, можно встретить в [CLAR89,
RAPP82, RAPP85, SCHL70, WEIS91, WEYU90, WEYU94A], Данные книги реко­
мендуются для дополнительного ознакомления с рассматриваемыми концепциями.

1 Задается транзитивным замыканием отношения «напрямую соединен с».


2 Для ортодоксов модели потоков данных, обсуждаемые в данной книге, — это интерпретации
формально определенных критериев структурного тестирования для потоков данных, но вновь истол­
кованные в терминах поведенческого тестирования. Оправдание для такой интерпретации основано
не на каком-либо глубоком теоретическом анализе, а на общем смысле и опыте. Как бы то ни было,
хотя большая часть поведенческого тестирования является эвристическим и в его основе лежат факты,
полученные опытным путем, подобное тестирование должно в максимальной степени соответствовать
и быть основанным на более фундаментальных, основополагающих структурных методах.
134 Глава 5 • Тестирование потоков данных

Методы тестирования потоков данных более эффективны, чем методы тести­


рования потоков управления. Более эффективны в том смысле, что они могут об­
наружить больше ошибок. Они также более эффективны с точки зрения теории,
поскольку модель помогает нам создать все тесты, которые мы могли бы создать
с помощью тестирования потоков управления и еще некоторые дополнительные
тесты. Однако за это приходится расплачиваться. Чтобы достичь более эффек­
тивного тестирования, вам приходится проделать больше работы. Больше работы,
во-первых, при проектировании тестов, а, во-вторых, при проверке результатов
тестирования. Приведенные ниже методы тестирования, используемые в графах
потоков данных, расположены по степени возрастания их эффективности.
Покрытие ввода/вывода. Рассмотрим каждый выходной узел отдельно (по­
мните, что граф потока данных имеет по одному выходному узлу на каждый вы­
вод). Для каждого выходного узла используйте набор входных значений, которые
приводят к определенному значению вывода. В этой технике есть очевидное сла­
бое место. Мы обеспечим покрытие входных и выходных узлов и, возможно, неко­
торых промежуточных узлов, но если среди них имеется отдельный предикат вы­
бора, мы можем быть уверены в том, что используется только одно значение этого
предиката. Другие не будут протестированы. Эта проверка слишком слаба, чтобы
быть нам полезной. Она гарантирует нам только то, что программное обеспечение
работает для одного набора входных данных и, очевидно, не делает ничего плохо­
го —например, сбоя. Забудьте об этом методе.
Ввод/вывод + все предикаты. Давайте попробуем нечто посильнее. Усилим пок­
рытие ввода/вывода, следя за тем, чтобы все предикаты (включая предикаты пото­
ка управления для циклов и другого необходимого упорядочения) были проверены
для обоих значений истинности и аналогично для предикатов в операторах CASE.
Это уже лучше, но все же недостаточно хорошо. Что, если есть промежуточ­
ные вычисления, результаты которых не используются? Мы не сможем их обна­
ружить, не так ли? В качестве другой возможности рассмотрим следующий вари­
ант. Мы рассчитываем величину X, но не используем ее, поскольку где-то позже
на этом пути мы пересчитываем величину X без использования первого значения.
В этом случае селекторы отсутствуют. Вычисление чего-либо без последующего
использования полученного результата —это, скорее всего, ошибка, которая чаще
всего является лишь неоправданной тратой ресурсов, но иногда может быть опас­
на. Тут стоит взглянуть на дело со стороны. Наша модель основана на том, что, как
мы надеемся, является корректной реализацией исходных требований. Но мы же
тестируем реализацию, содержащую ошибки. Следовательно, промежуточное вы­
числение, выход которого не используется, по всей видимости, является ошибкой,
и мы должны стараться ее обнаружить.
Процитируем Раппса и Веюкера [RAPP82]: «Нельзя быть уверенным в про­
грамме, если нельзя увидеть эффект от использования величины, полученной... в
ходе каждого вычисления».
Если мы просто проверили все узлы с предикатами (как потока управления,
так и выбора данных), мы добились большего, чем тестирование ветвей потока
управления (из-за проблемы составных предикатов), но мы не получили бы всех
тех преимуществ, которые дает тестирование потоков данных.
5.4. Методы 135

Частичное покрытие узлов. Предыдущие методы обеспечивали покрытие


некоторых узлов и некоторых связей, но при этом не гарантировали, что будет
обеспечено покрытие всех узлов и/или всех связей. Таким образом, зная, что
цель нашей стратегии, по крайней мере, обеспечить покрытие вычислительных
узлов нашей модели, давайте удостоверимся, что так оно и есть на самом деле.
Это называется стратегией всех определений, поскольку каждый вычислитель­
ный узел в нашей модели потока данных соответствует определению некоторой
переменной. Заметьте, что это не обеспечивает покрытия связей. Таким обра­
зом, эту стратегию нельзя прямо сравнивать со стратегией ввод/вывод + преди­
кат, описанной ранее.
Что эта стратегия значит? Мы создаем и выполняем достаточно тестов, чтобы
быть уверенными в проверке каждого вычислительного узла нашей модели. Это
означает, что каждая функция была выполнена хотя бы один раз и дала (по край­
ней мере, мы надеемся на это) правильное значение для этого случая. Заметьте,
что мы отвечаем за проверку промежуточных результатов, поскольку тестирова­
ние каждого вычислительного узла подразумевает проверку вычисления, сделан­
ного в этом узле.
Стратегия все определения (ВО) представляет определенный интерес, по­
скольку в ранней литературе, посвященной эвристическому тестированию пото­
ков данных, обычно предлагался этот метод [BEND70, BEND85, HERM76]. Здесь
наши методы основаны на формальной, проверенной теории [FRAN88, RAPP82].
ВО также упускает слишком многое. Например, этот метод может пропустить все
узлы выбора и все циклы в модели. Этого достаточно, чтобы отказаться от такого
метода. Нам нужно что-то более сильное.
Все узлы. Следующая очевидная ступень — убедиться, что мы покрываем все
узлы, а не только вычислительные. Это, несомненно, более сильное утверждение,
потому что мы хотим быть уверены, что в дополнение к вычислительным узлам
мы обеспечиваем покрытие всех узлов выбора данных и узлов потока управления.
Но это недостаточно сильно, поскольку, например, не дает гарантии, что мы про­
верили все варианты для предикатов выбора и потока управления. Требуется не­
что еще более сильное.
Покрытие связей (все использования). Следующая логическая ступень —охват
всех связей в графе потока данных. Она соответствует стратегии всех использова­
ний. Всякий раз, когда вычисление выполнено, мы будем проверять каждое ис­
пользование результата этого вычисления в последующей обработке. Это, ко­
нечно, подразумевает проверку всех промежуточных вычислений, а не только
конечных выводов. Но это не означает тестирования каждого возможного пути в
программе. Это даже не тестирование всех возможных путей между точкой опре­
деления и местом его последующего использования.
Все использования + циклы. Существует много не охваченных здесь других
стратегий тестирования потоков данных. Для того чтобы получить общее пред­
ставление о них, смотрите [WEYU94A] в [MARC94]. Нам следует попытаться
не допускать циклов в наших моделях потока данных, но это не всегда возможно.
Если у вас есть подобные циклы, тогда разверните модель и добавьте к вашим тес­
товым вариантам покрытие связей развернутой модели1.
136 Глава 5 • Тестирование потоков данных

5.4.3. Построение модели


Настало время прекратить теоретизирование и начать построение модели. Давайте
разработаем упрощенный вариант для строк с 54 по 60 формы 1040. Вот исход­
ный материал, скопированный из документа ВНС с минимальными изменениями,
введенными для ясности.
54: Federal Tax W ithheld (Удержанный федеральный налог)
55: 1994 E stim ated Tax Payment (Выплата налога со всех видов дохода в
1994) and Amount A p p lie d from 1993 Return (Сумма, заявленная в
декларации 1993)
56: Earned Income C r e d it (Налоговые льготы, предоставляемые получателям
заработной платы)
57: Amount Paid w ith Form 4868 (E xte n sio n Request) (Сумма, уплаченная в
соответствии с формой 4686 (Просьба о продлении))
58а: Excess S o c ia l S e c u r it y and RRTA Tax W ithheld (Налог на превышение
социального обеспечения)
59: Другие выплаты в соответствии с формой 2439 или формой 4136
60: Общий платеж: сумма строк с 54 по 59.

Первое приближение нашей модели почти полностью совпадает со строками


налоговой декларации и лишь имеет слегка более формальный вид. В глубине
души я надеюсь использовать инструмент, который поможет мне проверить пол­
ноту и непротиворечивость этой спецификации, так что заблаговременная форма­
лизация —хорошая идея.
54: 60: Federal_T ax_W ithheld (Удержанный_федеральный_налог)
55: 60: 1994_Estimated_Tax_Payment
(Выплата_налога_со_всех_видов_дохода_в_1994) and
Am ount_Applied_from_1993_Return
(Сумма_заявленная_в_декларации_1993 )
56: 60: Earned_Incom e_Credit
(Налоговые_льготы_предоставляемые_получателям_заработной_платы)
57: 60: Amount_Paid_with_Form_4868 (Extension_Request)
(Сумма_уплаченная_в_соответствии_с_формой_4868
(Просьба о продлении))
58а: 60: E x c e s s _ S o c ia l_ S e c u rity and RRTA_Tax_Withheld
(Налог_на_превышение_социального_обеспечения)
59: 60: другие_выплаты (в соответствии с формой 2439 или формой 4136)
60: Общий Платеж: сумма строк с 54 по 59.

На самом деле это неправильно, не так ли? Строка 55 по сути является суммой
двух слагаемых, строка 58а — сумма двух слагаемых, и строка 59 тоже является
суммой двух слагаемых (форма 2349 и форма 4136: Налог со всех видов дохода
в 1994 и Сумма, взятая из декларации 1993, соответственно). Мы создадим более
детальную модель.
54: 60: Federal_T ax_W ithheld (Удержанный_федеральный_налог)
55a: 55: 1994_Estimated_Tax_Payment
(Выплата_налога_со_всех_видов_дохода_в_1994)
55b: 55: Am ount_Applied_from_1993_Return 1

1 Нам нужна одна из стратегий «всех использований», но не настолько мощная, как проверка всех
путей, которая в контексте поведенческого тестирования просто неосуществима
5.4. Методы 137

(Сумма_заявленная_в_декларации_1993 )
55: 60: 55а + 55Ь
56: 60: Еа rned_Income_Credi t
(Налоговые_льготы_предоставляемые_получателям_заработной_платы)
57: 60: Amount_Pa i d_wi th_Form_4868 ( Extens i on_Request)
(Сумма_уплаченная_в_соответствии_с_формой_4868
(Просьба о продлении))
58а 1: 58а: E xce ss_ S o cia l_ S e cu rity_ T a x_ W ith h e ld
(Налог_на_превышение_социального_обеспечения)
58а 2: 58а: Excess_RTTA_Tax_W ithheld (Налог_на_превышение_РРТА)
58а: 60: 58a1 + 58a2
59а: 59: Другие_выплаты_в_соответст8ии с Формой 2439
59Ь: 59: Другие выплаты в воответствии с Формой 4136
59: 60: 59а + 59Ь
60: Total Payments (Общие выплаты):= 54 + 55 + 56 + 57+ 58а + 59

Последняя строка мне не нравится из-за ее двусмысленного представления.


Речь шла об узлах 54, 55 и так далее, или об их значениях? Будет лучше внести яс­
ность и заменить эту строку такой:
60: T o tal Payments: С54 + С55 + С56 + С57 + С58а + С59

В этой модели я сделал некоторые предположения, которые могут быть, а мо­


гут и не быть верными. Во всех случаях, когда я детализировал узел (55,58а и 59),
я предполагал, что входные данные могут прийти из ниоткуда, из одного или всех
доступных источников. Эти узлы не являются узлами выбора данных. Узлы вы­
бора должны иметь дело с взаимоисключающими случаями. Например, строка
38 —это узел выбора, так как в нем делается выбор между взаимоисключающими
случаями. Откуда вам об этом узнать? Вы должны понять приложение и его зада­
чи. Давайте смоделируем только одну строку 38 и то, что она за собой влечет.
38 Налог.Отметить, если из а [ ] Tax T ab le (Таблицы налогов), b [ ] Tax Rate
Schedule (Схемы налоговых ставок), с [ ] C a p ita l Gain Tax Worksheet (Таблицы налога
на капитальную прибыль) или d [ ] Формы 8615. е. Сумма из форм(ы) 8814.

Я не являюсь специалистом по налогам, так что я должен был читать инструк­


ции ВНС и руководство по налогам, чтобы понять, что делать с пунктом е. Пункт е
должен быть добавлен в налог, несмотря на то, что в форме это не указано. Пункты
а, Ь, с и d — взаимоисключающие и формируют соответствующий узел выбора.
Ниже приводится модель для данного случая.
38а: 38х: часть_налога (Используйте Tax T able (Таблицу налогов))
38Ь: 38х: часть_налога (Используйте Tax Rate Schedule (Схему налоговых
с т а в о к ))
38с: 38х: часть_налога (Используйте C a p ita l Gain Tax Worksheet (Таблицу
налога на капитальную прибыль))
38d: 38х: часть_налога (Из Формы 8615)
38х: ВЫБОР (исходя из правил 8НС) 38а
38Ь
38с
38d
38е: 38: Сумма_из_Форм(ы) 8814
38: С38х + С38е
138 Глава 5 • Тестирование потоков данных

5.4.4. Выбор основного порожденного подграфа


Нам надо рассмотреть несколько различных ситуаций для выбора порожденного
подграфа — эквивалента путей потока управления в диаграммах потока данных.
То, что мы делаем, зависит от того, что представляет собой граф потока данных.
1. Нет узлов выбора, нет узлов потока управления (и нет циклов).
2. Только потоки данных и узлы выбора.
3. Только узлы предикатов потока управления, без узлов выбора.
4. Узлы предикатов потока управления и узлы выбора.
5. Циклы.
Случай 1: Чистые потоки данных
Следующую процедуру необходимо проделать для каждого выходного узла.
Выберите выходной узел. Проследуйте в обратном направлении от выходного
узла ко всем соединенным с ним узлам. Проследуйте от этих узлов в обратном на­
правлении к тем узлам, которые, в свою очередь, соединяются с ними, и так далее,
пока не достигнете входных узлов (для данной модели). Теперь у вас есть порож­
денный граф потока данных. Символически ситуация проиллюстрирована следу­
ющим образом:

U l, U2 и U3 —выходные переменные. А, В и С —наборы входных переменных.


Средняя область содержит вычислительные узлы. U1 зависит только от входных
переменных из набора A. U2 зависит как от переменных из А, так и от перемен­
ных из В, a U3 зависит только от переменных из С. У нас есть три набора тестов,
соответствующих U l, U2 и U3. Если здесь нет узлов выбора и нет узлов потока
данных, вам потребуется только один тестовый вариант на одну выходную пере­
менную. Заметьте, что каждый порожденный подграф будет содержать (возмож­
но) различные вычислительные узлы в области ВЫЧИСЛЕНИЕ. Например, нам
следует ожидать, что вычислительные узлы, относящиеся к U3, не будут перекры­
5.4. Методы 139

ваться с узлами, соотносящимися с U1 и U2. Некоторая часть вычислительных


узлов (но не все) будет, вероятно, использоваться как в U1, так и в U2.
Случай 2: Только потоки данных и узлы выбора
Начните, как и раньше, с порожденного подграфа для каждой выходной перемен­
ной. Однако когда вы достигнете узла выбора, вы должны включить в порожден­
ный подграф каждый потенциально выбираемый вариант. Результатом будет не­
что вроде объединенного порожденного подграфа, поскольку в данном случае
имеется множество альтернативных путей. Каждый объединенный порожденный
подграф приведет к получению целого набора тестовых вариантов. Рассмотрите
отдельно каждый объединенный порожденный подграф.
Допустим, что в порожденном подграфе есть только один узел выбора. Выберите
величину для каждого значения предиката выбора и затем исключите из порож­
денного подграфа все потоки данных, которые не принимают участия в определе­
нии этой величины. Если, например, в строке 38 мы выберем 38а (Использовать Tax
Table (Таблицу налогов)), то нам следует исключить из порожденного подграфа по­
токи данных, приводящие к строке Использовать Tax Rate Schedule (Схему налого­
вых ставок). Использовать Capital Gain Tax Worksheet (Таблицу налога на капитальную
прибыль) и Использовать форму 8615.
Порожденный подграф, основанный на U, включает в себя три вычислитель­
ные области, наборы данных А, В, С, D и узел выбора. Если мы выберем величи­
ну X, которая зависит только от наборов данных А и В, мы исключаем из порож­
денного подграфа наборы данных С и D и вычислительную область Y. Напротив,
если мы выберем величину Y, то в этом случае исключаем набор А и вычислитель­
ную область X, поскольку входные наборы данных В, С, и D используются для вы­
числения Y и U по мере прохождения порожденного подграфа.

Предположим, что в порожденном подграфе имеется два или более предикатов


выбора. У нас опять есть два случая: при обратном движении по потокам (от вы­
хода к входу) они могут соответствовать или ветвлению, или слиянию потоков
140 Глава 5 • Тестирование потоков данных

данных. Сначала мы рассмотрим более простой случай, при котором в двух пре­
дикатах выбора происходит ветвление потоков. Это изображено на следующем
рисунке.

Мы начинаем с разделения на порожденные подграфы всех выходных пере­


менных. Так же, как и прежде, выбираем одну из переменных и определяем по­
рожденный подграф для этой переменной. Как и раньше, первый встреченный
нами предикат выбора делит граф на несколько порожденных подграфов, каж­
дый из которых приводит к набору тестовых вариантов. На рисунке есть порож­
денный подграф для W, приводящий только к одному тестовому варианту, и еще
один порожденный подграф для V. Следуя от V в направлении входных узлов, мы
встречаем второй узел выбора, который снова порождает два варианта, приводя
к порожденному подграфу для X, включающему наборы входных переменных А,
В и другому набору для Y, включающему наборы входных переменных В, С и D.
Помните, что узел выбора может иметь много ветвей, и вы должны разрабатывать
отдельный набор тестов для каждой ветви.
И теперь рассмотрим последний случай, в котором потоки данных сливаются
и следуют назад вместе. Если мы возьмем порожденный подграф V для нижнего
узла выбора и проследуем по нему вверх, мы натолкнемся на другой узел выбора,
приводящий к двум новым порожденным подграфам и двум тестовым вариантам,
соответствующим выбору X или Y. Порожденный подграф W, однако, идет назад
к тому же узлу выбора (X, Y) где снова имеется возможность выбора из двух вари­
антов. Приведет ли это к еще двум тестовым вариантам или только к одному?
Это зависит от того, насколько тщательно вы хотите тестировать. Если вы вы­
берете только один вариант для W, что дает только один порожденный подграф
(либо X, либо Y), тогда у вас будет один дополнительный тест. При более тщатель­
5.4. Методы 141

ном (и требующем больших затрат) тестировании вам следует взять оба порож­
денных подграфа. В нашем примере это добавляет только один тест, но если у нас
есть много узлов выбора, расположенных один за другим в каждом порожден­
ном подграфе, разница в подходах может стать разительной. Эти два метода соот­
ветствуют применению того, что формально известно как критерий всех исполь­
зований (ВИ) (берется какой-либо один порожденный подграф, который влияет
на значение W) и критерий Всех путей-определение-использование (ВПОИ) (бе­
рется каждый порожденный подграф, влияющий на значение W). ВПОИ —более
полный метод, чем ВИ, но требует бблыпих трудозатрат. Исходя из эмпирическо­
го доказательства, приведенного в [WEYU90], вы сможете получить больше пре­
имуществ, выбрав ВИ. Таким образом, убедитесь, что вы включили по крайней
мере один порожденный подграф для каждого выхода, а не все возможные порож­
денные подграфы, которые появляются вследствие всех возможных комбинаций
выбора в селекторах (и, как мы увидим, всех комбинаций значений для предика­
тов потока управления и условий циклов).

Случай 3: Предикаты потока управления без узлов выбора


Этот случай обрабатывается тем же способом, что и узлы выбора. Начиная с конца
графа, от выходных переменных, создайте порожденный подграф. Правда, здесь
есть отличие от предыдущего варианта. В узле выбора данных в порожденный под­
граф войдет только одна входящая связь. То есть каждая входящая связь создает
новый порожденный подграф. В узле потока управления (например, IF-THEN-ELSE
или CASE) каждая исходящая связь создает новый порожденный подграф. По этой
причине, возможно, будет проще создавать порожденный подграф для потоков
управления начиная от входов, а не от выходов. Однако мы имеем дело с моделя­
142 Глава 5 • Тестирование потоков данных

ми потока данных, и элементы потока управления встречаются здесь (по крайней


мере, на это следует надеяться) лишь случайно. Ситуация показана на следующем
рисунке.

Начните создание порожденного подграфа так же, как и раньше, с выхода U


(для каждого выхода). Он приводит в вычислительные области С1 и С2 и связан­
ные с ними источники данных II и 12 (которые могут перекрываться). Продолжив
создание порожденного подграфа, вы достигнете узла потока управления, кото­
рый по определению означает, что за ним возможен только один из двух альтерна­
тивных вариантов. То есть вы должны выбрать либо область С 1, либо область С2
(и связанные с ними потоки данных). Каждый вариант порождает один тест. Для
обоих тестов нужны выходы из области В и набор данных 14. Существует хорошая
практика создания порожденных подграфов:
1. Для узлов выбора потоков данных начинайте создание порожденного под­
графа с входящих в узел связей.
2. Для узлов потока управления начинайте создание порожденного подграфа
с исходящих из узла связей.
Выбор пути при тестировании потока управления заключается в выборе по­
рожденного подграфа, начинающегося с узла BEGIN1. Создание порожденного
подграфа при наличии потока управления в графе потока данных усложняется,
поскольку в целом мы хотим создать порожденный подграф начиная с выхода.
Однако присутствие узлов потока управления вынуждает нас менять направле­
ние и исключать из порожденного подграфа то, что мы могли включить в него
раньше (до того как осознали, что это был узел потока управления).
Прежде чем вы станете это делать, проверьте, нужна ли вам часть модели с по­
током управления. В предыдущем примере такой необходимости не было. Мы
могли бы, например, заменить узел потока управления узлом выбора данных, ко­

1 Говоря формально, именно порожденный подграф определяется выбранным путем начиная от


узла BEGIN и заканчивая узлом EXIT. То есть выберите путь, а затем создайте порожденный подграф,
который объединяет другие порожденные подграфы, полученные для каждой активной переменной
вдоль пути.
5.4. Методы 143

торый осуществлял бы выбор между выводами областей С1 и С2 и затем переда­


вал бы их в область СЗ. Можете ли вы поступить подобным образом —зависит от
приложения и от природы используемых объектов. Помните, что не важно, как
именно может быть (или не может быть) запрограммировано приложение. Важно,
насколько правильно модель отражает смысл требований. Вы ничего не можете
сделать с основными (существенными) потоками управления и синхронизации.
Вы можете лишь экспериментировать с каким-либо удобным примером. Если ра­
зумно примененный в вашей модели узел потока управления устраняет дублиро­
ванные потоки данных, то это хорошо. Если он прибавляет сложности и затрудня­
ет построение порожденного подграфа, то это плохо.
Случай 4: Смешение предикатов потока
управления и узлов выбора потоков данных
Этот случай —комбинация двух предшествующих ситуаций, так что будьте акку­
ратны в построении ваших порожденных подграфов. Вам следует избегать сме­
шанных моделей, поскольку в них легко запутаться. В отличие от программиро­
вания, путаница приведет не к созданию ошибки, а к бесполезной трате времени
и созданию бесполезных или невыполнимых тестов.
Если у вас есть смешанная модель, как с узлами потока управления, так и с уз­
лами выбора, вам лучше пометить узлы каждого типа, поскольку вы будете часто
колебаться при построении порожденных подграфов.
Случай 5: Циклы
Модели потока данных просто неудобны для проверки циклов. Правильный под­
ход — выполнить полную развертку однократного прохода цикла и затем ввести
узел выбора данных для каждого значения. Например, если вы предпочтете три
варианта, у вас получится: отсутствие прохождения цикла, однократное прохож­
дение, двукратное прохождение и узел выбора для этих трех случаев.

5.4.5. Итоговый пример


Теперь создадим модель, которую мы можем использовать для активизации теста
и для завершения этой главы. Она основана на бланке ИПС номер 1 (Форма 1040,
Строка 23а/Ь). После небольшой переработки этого бланка, сделанной для того,
чтобы придать ему более формальный вид, мы имеем следующую модель.
У Вас У Вашего Супруга(и)
С1: Мин ($2000. ИПС_СопЪП Ь_1994 ________ ________
(Вклад_ ИПС_в_1994))
С2: Income (Доход) ________ ________
СЗ: Мин ( C l. С2) (выход) 1040 23а 1040 23Ь
Неработающий(ая) супруг(а)
С4: Мин (С2а. $2250) ________
С5: Выход_из_СЗ ________
С6: Строка_5 - Строка_4 ________
С7: Мин ($2000. 94_вклад_супр) ________
С8: Мин (Строка_6. Строка_7) (выход) ________
144 Глава 5 • Тестирование потоков данных

Я буду строить эту модель для случая, когда ваш супруг(а) (если он(а) есть) не
работает, и вы можете (или не можете) внести взнос в ИПС за него. Полная мо­
дель (в которую включен работающий супруг) оставлена в качестве упражнения
для самостоятельного выполнения. Вы можете предположить, что в этой модели
некоторые из узлов и связей на самом деле не нужны, например, такие как: С 1а,
СЗа, С4, С5 и С7. Я сохранил все узлы, следующие за узлом выбора, в качестве
меры предосторожности и для того, чтобы быть уверенным в том, что узел выбора
в этой модели явный, а не скрытый, по аналогии с формой. Строка 5 (узел 5) была
сохранена, поскольку подобная строка имеется в форме ВНС, и у нас будет воз­
можность проверить ее значение.
k l: CCla константа = $2000
СС7
BCla: CCla ВХОД ваш_взнос_в_ИПС_94
С2а: ССЗа ВХОД your_94_wages
(Ваша_заработная_плата_в_1994 ??)
СС4а
ВС7: СС7 ВХОД взнос_супруга_в_ИПС_94
к2: СС4а константа = $2250
CCla: C la ВЫБРАТЬ мин m in (k l, BCla)
C la : ССЗа
ССЗа: СЗа ВЫБРАТЬ мин m in (C la . С2а)
СЗа: ВЫХОДа ВЫХОД в Строку 23а Формы 1040
С5
С5: Сб (замечание: спецификация ВНС неправильна,
вместо "СтрокаЗ" должно быть сказано
“СтрокаЗа" - подобные пустяки как раз и порождают ошибки)
СС4а: С4 ВЫБРАТЬ мин (С2а. к2) (замечание: в этом месте еще одна ошибка
ВНС)
С4: Сб
Сб: СС8 С4-С5
СС7: С7 ВЫБРАТЬ мин (ВС7. k l)
С7: СС8 ВЫБРАТЬ мин (Сб. С7)
СС8: С8 ВЫХОД в строку 23Ь формы 1040

Сначала мы выбираем простые порожденные подграфы. Одним из них являет­


ся случай взноса в ИПС, вводимого в строку 23а формы ВНС 1040. Порожденный
подграф, начинающийся от выходного узла ВЫХОДа, содержит узлы kl, BCla,
CCla, С1а, ССЗа, C2a, СЗа, ВЫХОДа и соответствующие связи. Тут имеются два
узла выбора (и предикаты), но только три возможности, зависящие от того, какая
из следующих величин меньше: $2000, 1994 Взнос в ИПС, или заработная плата в
1994 году. В силу этого наш порожденный подграф приводит к трем тестовым ва­
риантам, которые следует активизировать позже.
Вывод в строке 8 для супружеского взноса в ИПС более сложен из-за того, что
выбор этого вывода приводит к включению в наш порожденный подграф всего
графа, за исключением узла ВЫХОДа. Я буду строить свои порожденные графы
методично, двигаясь от конца к началу, и буду пытаться обеспечить покрытие свя­
зей и узлов, не покрытых предыдущим тестовым вариантом. Получившиеся це­
почки выглядят следующим образом.
Тест 1: С8, СС8. Сб. С5. СЗа. ССЗа. C la . CCla. BCla. С4. СС4а. к2
Тест 2: С8. СС8. Сб. С5. СЗа. ССЗа. C la . CCla. k l. С4. СС4а. С2а
5.4. Методы 145

Тест 3: С8. СС8. Сб. С5. СЗа. ССЗа. С2а. С4. СС4а
Тест 4: С8. СС8. Сб. С5. СЗа. ССЗа. C la . CC la. k l . С4. СС4а. к2
Тест 5: С8, СС8. С7. СС7. ВС7
Тест б: С8. СС8, С7. СС7. К1

Заметьте, что я выписывал имена узлов, а не связей. В общем случае вы долж­


ны выписать все связи или ясно показать, что вы определяете набор сегментов
путей через граф потока данных, которые определяют порожденный подграф.
Например, более точное представление будет таким:
Тест 1: С8. СС8. Сб. С5. СЗа. ССЗа. C la . CCla. ВС1а/С6. С4. СС4а. к2

Я использовал сокращенную запись, поскольку в данном случае она недву­


смысленна. В случае более сложного потокового графа она может быть неод­
нозначной и для точной идентификации маршрута будет недостаточно просто пе­
речислить имена узлов.
Заметьте, что в отличие от тестирования потока управления, где мы следовали
только вдоль одного набора стрелок, в данном случае, поскольку Сб содержит вы­
числение, затрагивающее С4 и С5, нам следует включить в порожденный подграф
обе связи. Для узлов выбора, однако, в порожденный подграф включается ветвь
только для выбранной входящей связи. Может быть, и есть возможность обойтись
меньшим количеством тестов, но я не слишком к этому стремился. Задача заклю­
чается в том, чтобы обеспечить покрытие связей, а не минимизировать количест­
во тестовых вариантов. Узлы выбора здесь коварны, потому что они основаны на
сравнении двух величин, я имею в виду MIN (А, В). Если обе величины одинако­
вы, вы не знаете, какую связь следует использовать, так что это не слишком хоро­
шая основа для тестовых вариантов (по крайней мере, для попытки обеспечить
покрытие связей).

5.4.6. Активизация
Каждый тест соответствует порожденному подграфу. Если порожденные подгра­
фы были определены корректно, тогда для активизации одного подобного порож­
денного подграфа достаточно задать только его входные величины. Активизация
происходит по большей части так же, как это было описано для потоков управ­
ления, за исключением того случая, когда вы можете решить, что проще начать с
выхода и двигаться в направлении входов. Если же в порожденном подграфе нет
узлов выбора или узлов потока управления, об активизации не стоит и говорить.
Любые приемлемые входные значения подойдут.
В случае существования узлов выбора или узлов потока управления следует
выполнить несколько процедур.
1. Обратите внимание на минимальные и максимальные значения для каж­
дого входа. Если значения составляют некоторое множество, запишите все
значения из него.
2. Двигайтесь по всем ветвям порожденного подграфа в обратном направле­
нии (к началу), отмечая пути, которые достигают входов без прохождения
через узлы выбора (потоков данных или потоков управления). Вы можете
146 Глава 5 • Тестирование потоков данных

пока игнорировать эти части порожденного подграфа, потому что для вхо­
дящих данных, скорее всего, нет ограничений.
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. Методы 147

5.4.7. Предсказание итогов


Здесь не обсуждаются проблемы, касающиеся предсказания итогов, которые
бы не рассматривались в главе 3. Однако вы вряд ли будете строить модель­
ную программу на основе модели потока данных, потому что в большинстве
языков программирования не слишком удобно проектировать потоки данных.
Поскольку в вашей модели не должно быть очень много потоков управления,
для построения оракула хорошо подойдет электронная таблица. Каждая ячейка
таблицы —это явный узел, при этом она обеспечивает прямые отношения пото­
ков данных между формулами в ячейках. Таблицы по своей природе являются
удобным средством для работы с потоками, и так же, как и в случае графов по­
тока данных, присутствие в них элементов потока управления сильно усложня­
ет ситуацию.

5.4.8. Проверка соответствия пути


Это не проверка путей как таковая, это проверка узлов. Вы не получите боль­
шого преимущества от тестирования потоков данных и останетесь незащищен­
ными от случайной корректности, если не будете проверять промежуточные
вычисления, то есть, например, значения в узлах. Более эффективные методы
тестирования подразумевают большую работу, а проверка этих промежуточных
вычислений может оказаться очень трудоемкой. Таким образом, и для них вам
нужен оракул.
Под «тестируемостью» здесь понимается возможность проверить промежу­
точные вычисления. Я не знаю, как это сделать без использования логических
операторов проверки, заранее вычисленных выходных величин и символьных от­
ладчиков.
Одним из преимуществ объектно-ориентированного программирования явля­
ется то, что, наряду с надлежащим сокрытием информации, минимизирована ве­
роятность побочных эффектов, и результатом должна быть более устойчивая ра­
бота системы. Но сокрытие информации не должно означать, что тестировщик
действительно не имеет доступа к этим данным. Электрические системы в вашем
автомобиле имеют разъемы, на первый взгляд не служащие никакой полезной
цели. Вам они не нужны и не стоит экспериментировать с ними. Но спросите ва­
шего механика, насколько важны эти тестовые разъемы. Подобным же образом
материнская плата в вашем ПК имеет разъемы и перемычки, необходимые только
для тестирования, и нужно быть смелым и глупым одновременно, чтобы играть с
ними. Но для тестирования они действительно полезны.
Тестирование — законное основание для доступа к так называемым собствен­
ным данным и для снятия завесы, скрывающей информацию. Если вы тестируете
ваше собственное программное обеспечение, используйте многочисленные логи­
ческие операторы проверки как базовые точки тестирования. Если вы тестируете
стороннее программное обеспечение, окажите на его разработчика максимально
возможное давление, чтобы заставить внедрить нужные точки тестирования или
логические операторы проверки.
148 Глава 5 • Тестирование потоков данных

5.5. Анализ приложений


5.5.1. Виды приложений
Приложения охватывают почти весь спектр существующего программного обес­
печения, но я бы не использовал тестирование потоков данных для низкоуровне­
вого тестирования программного обеспечения, в котором имеется много необхо­
димых потоков управления. Наиболее естественно использовать рассматривае­
мый метод для следующих приложений:
1. Объектно-ориентированное программное обеспечение. ООПО — парадиг­
ма, основанная на потоках данных, вот почему графы потоков данных час-
, то являются частью методологии разработки ООПО. Если вы используе­
те для этой цели тестирование потоков данных, вы должны допускать, что
объекты были должным образом протестированы на более низком уровне,
так что вы можете не сомневаться в их надежности и заменить каждый из
них соответствующим узлом. Далее вы концентрируетесь на том, правиль­
ные ли объекты активизируются, правильные ли сообщения проходят, и
так далее.
2. Тестирование интеграции. Главная проблема с интеграцией не в том, рабо­
тают ли интегрированные компоненты (это должно быть проверено в ходе
тестирования модулей), а в том, правильно ли они соединены и сообщают­
ся друг с другом. Каждый компонент моделируется узлом, а граф потока
данных может быть деревом вызовов функций программы. Это замечатель­
но, поскольку у нас есть инструменты для отображения деревьев вызовов.
Печально в данном случае то, что обычного дерева вызовов будет недоста­
точно. Если имеются глобальные переменные, вы должны рассматривать
потоки данных для них. И поскольку некоторые вызовы и межкомпонент­
ные связи могут быть динамическими, статическое дерево вызовов, опре­
деляемое компилятором/редактором связей, не даст вам полной картины —
но это будет хорошим началом работы по ее созданию.
3. Электронные таблицы. Электронные таблицы максимально адаптированы
к чистому языку моделирования потока данных. Не пренебрегайте элек­
тронными таблицами, считая их лишь вспомогательным средством. Они
представляют собой реальное средство программирования для людей, со­
здающих сложные приложения для бизнеса, но имеющих мало инстру­
ментов и методов для их проверки. Однако если вы покупаете готовые
электронные таблицы и планируете придать толчок вашему бизнесу с их
помощью, некоторое тестирование перед их полноценным использованием
будет не лишним.

5.5.2. Предположения об ошибках


Все ошибки, для поиска которых предназначено тестирование потока управ­
ления, можно найти и при помощи тестирования потоков данных, иосколь-
5.5. Анализ приложений 149

ку оно включает в себя тестирование потоков управления как составной эле­


мент. Поскольку мы избегаем несущественных потоков управления в моделях
потока данных, мы допускаем, что программисты умеют сами избавляться от
простых ошибок потока управления. Это смещает акценты в сторону поиска
ошибок данных. В моей систематике ошибок [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]. Если у вас есть средство проектирования, поддерживающее
диаграммы потоков данных, справьтесь у продавца, почему оно не обеспечивает
автоматизацию проектирования тестов.
150 Глава 5 • Тестирование потоков данных

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, но
задействуйте логику, чтобы определить, может ли быть использована крат­
кая форма. Используйте граф только потоков данных, затем проделайте то
же самое с использованием модели графа потоков управления и покрытием
5.7. Вопросы для самопроверки 151

условий предикатов и переделайте задание, используя смесь модели пото­


ков управления и модели потоков данных.
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 (Заявление о продлении сро­
ка). Форма целиком.
11. Форма 2210, Неполная оплата налогов, (а) только строка 1, (б) часть II,
(в) часть III, (г) часть IV, раздел А, (д) часть IV, раздел В. Предположите,
что вы можете использовать краткий метод (Часть III) в случае, если не сде­
лали отметок в графах lb, 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.2. Основные термины 153

чальный узел, конечный узел, модель конечного числа состояний, граф, входящая
связь, ввод, интеграция, промежуточный узел, связь, покрытие связей, вес связи,
цикл, тестирование цикла, модельная программа, узел, покрытие узлов, итог, ис­
ходящая связь, путь, предикат, отношение, активизировать, порожденный под­
граф, спецификация, состояние, субмодель, системный тест, проект теста, путь
теста, тестирование, критерий соответствия.
Транзакция —единичная операция по обработке данных.
Маркер транзакции — метка (например, точка), которая отображает присут­
ствие транзакции на модельной связи.
Контрольная запись транзакции —гипотетическая или фактическая запись, кото­
рая содержит данные о транзакции. В фактической записи нет необходимости, одна­
ко во многих системах она присутствует. Там, где контекст позволяет, вместо термина
«контрольная запись транзакции» будет использоваться термин «запись транзакции».
Состояние транзакции — потенциально это значения всех данных в контроль­
ной записи транзакции или ее неявном эквиваленте. Но, как правило, состояние
выражают лишь частью данных записи, зачастую целым числом.
Тип транзакции — некое обозначение, например, целое число, которое исполь­
зуется для идентификации транзакций различных типов.
Стартовый узел — узел в модели графа потока транзакций, в котором транзак­
ция начинает нас интересовать. Это входной узел графа потока транзакций.
Завершающий узел —узел в модели графа потока транзакций, в котором транзак­
ция прекращает нас интересовать. Это выходной узел графа потока транзакций.
Задача —каждая задача в графе потока транзакций представлена узлом.
Узел ветвления — узел, в котором входящая транзакция выбирает одну из не­
скольких альтернативных исходящих связей. Так, на рисунке входящая транзак­
ция вышла на самую верхнюю связь.

Предикат ветвления — предикат, который управляет выбором одной из исхо­


дящих связей узла ветвления. Он может быть основан на значениях данных тран­
закции (то есть значениях в управляющей записи транзакции) или же на комби­
нации типа и состояния транзакции.
Управляющая входящая связь — по возможности не зависящая от значений
в записи входящая связь, которая определяет, какая из исходящих связей узла
Ветвления будет выбрана транзакцией. Узел ветвления с управляющей входящей
связью подобен железнодорожной стрелке (то есть «направляет»). Для каждой
управляющей входящей связи должен существовать ассоциированный с нею пре­
дикат. Управляющие входящие связи обозначены пунктирными линиями.
154 Глава б • Тестирование потоков транзакций

Узел соединения — транзакция, поступающая по любой из входящих связей


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

Узел порождения — узел, в котором входящая транзакция генерирует более


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

Узел расщепления — узел, в котором входящая транзакция (материнская) ге­


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

Узел слияния —узел, в котором две или более входящие транзакции (родитель­
ские транзакции) сливаются в новую, выходящую дочернюю транзакцию. После
узла слияния родительские транзакции перестают существовать.

Узел поглощения — узел с входящими транзакциями, одна из которых (хищ­


ник) поглощает другие (жертвы).
6.3. Отношения и модель 155

IХищник
Хищник

@ Жертва

Марковский узел — узел, действие которого (обработка, ветвление, порожде­


ние, расщепление и т. д.) зависит только от типа и состояния входящих транзак­
ций, но не от пути, по которому транзакция добралась до узла.
Марковский граф потока транзакций — граф потока транзакций, все узлы ко­
торого являются марковскими.

6.3. Отношения и модель


6.3.1. Основы
Материал, рассматриваемый в этом разделе, описывался также в [MURA89,
РЕТЕ81].
Объекты (узлы) — шаги процесса обработки данных посредством транзакций,
например, шаги программы. Узлы представляют собой интересующие нас дей­
ствия, которые трансформируют входящие транзакции и производят выходящие
транзакции и/или меняют состояние входящих транзакций. Узлы могут модели­
ровать не только программы, но и действия людей, сетевые операции и вообще все,
что имеет смысл. Предполагается, что узлы имеют свою собственную модель, будь
то модель потока управления, модель потока данных или какая-нибудь еще мо­
дель. Производимое обрабатывающим узлом действие зависит только от данных,
содержащихся в записях входящих транзакций. Считается, что модели обработки
транзакций являются марковскими.
Объекты (транзакции) — транзакция идентифицируется своей контрольной
записью (фактической или гипотетической). Эта запись содержит по меньшей
мере тип и состояние транзакции. Предполагается, что и все другие интересующие
нас данные содержатся в записи транзакции. Интерпретация данных в записи
транзакции не зависит от значений в любой другой записи транзакции.
Отношение (связи): «Непосредственно следует» —соединение узлов А и Б свя­
зью от А к Б, если выходящая из А транзакция обрабатывается затем узлом Б.
Вес связи — с любой связью может быть ассоциировано несколько маркеров
транзакций. Каждый маркер представляет одну транзакцию.
Мы будем моделировать часть обработки формы 1040, как если бы она была
сделана добропорядочным налогоплательщиком, который настаивает на том, что­
бы каждая операция совершалась в том же самом порядке, в каком она появля­
ется в форме. Внутренняя налоговая служба в США не предъявляет такого тре­
бования, и вы можете заполнять формы в том порядке, в каком это имеет смысл,
но такое поведение не слишком применимо к моделированию потока транзакций.
(Для этого больше подходят модели потока данных.) Заметьте, что сейчас мы мо­
делируем не компьютер или программу, хотя и могли бы. Мы моделируем, каким
156 Глава 6 • Тестирование потоков транзакций

образом Видения Вистерия (наш субъект) заполняет декларацию о подоходном


налоге.
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
6.3. Отношения и модель 157

Шаг 2: 12/12.1 Ф1040


Шаг 3: 1 2 .1 /1 2 .2 Ф1040. 12.1/С Б-С
Шаг 4: 12 .1 /1 2.2 Ф1040. С/12.2 Б-С. С/С-фин SC-C
Шаг 5: 12.2/13 Ф1040. С/С-фин Б-С

Предположим, что дети Видении ведут свой собственный бизнес, а Видения


заполняет за них налоговые декларации. Ее дети вносят данные в свои индиви­
дуальные Бланки С, если это необходимо, а она заполнит за них всех формы 1040.
Формы 1040 инициируются в узле 11 (только для этой подмодели). Они поступа­
ют в узел 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» — («последним пришел —
первым обслужен»). Транзакция, которая позже всех поступила в очередь, будет
обработана раньше всех. Подобная очередь является обрабатывающим стеком,
158 Глава 6 • Тестирование потоков транзакций

в котором входящие транзакции помещаются на вершину стека и удаляются


с вершины.
Пакет. При возникновении определенных условий, таких как определенное
число транзакций в очереди, или же в оговоренный момент времени обрабатыва­
ются все транзакции в очереди в пакетном режиме. При этом во время обработки
новые транзакции накапливаются в новой очереди.
Случайное обслуживание. Обслуживание осуществляется случайным обра­
зом — возможно, на основе вероятностного распределения по некоторой величи­
не в контрольной записи транзакции.
Очередь по приоритету. Каждая транзакция имеет свой приоритет. Этот при­
оритет может быть фиксированным или зависеть от свойств транзакции, на­
пример, от ее возраста. Каждая группа транзакций с данным приоритетом обра­
батывается как отдельная очередь, причем очередь с наибольшим приоритетом
обрабатывается первой. Внутри отдельной группы транзакций с данным приори­
тетом сервис может осуществляться по принципу FIFO, LIFO и т. д.
Множественная обработка. Для обработки очереди может использоваться
один сервер (односерверная очередь) или несколько серверов {многосерверная
очередь). Кроме правила упорядочения конкретной очереди, может существовать
правило выбора сервера. Например, в супермаркете можно выбрать, в какую из
очередей к кассам встать. В билетной кассе аэропорта, на почте, в банке нужно сто­
ять в основной очереди и ожидать обслуживания до тех пор, пока работник учреж­
дения не скажет «Следующий!»
Далее термин простая очередь будет использоваться для обозначения односер­
верной очереди без приоритета, обслуживаемой по принципу FIFO. Если правило
упорядочения не оговорено, то наиболее вероятно, что э го простая очередь. За ней
следует очередь, обслуживаемая по принципу FIFO в зависимости от приоритета.
Очередь с данным приоритетом обрабатывается по принципу FIFO, но первой об­
рабатывается очередь с наибольшим приоритетом, затем очередь с более низким
приоритетом и т. д. Если вы имеете дело с очередью, не являющейся простой, то
убедитесь, что очередность приоритетов и, если необходимо, правило выбора сер­
вера реализованы правильно.

6.3.4. Слияние и поглощение


Существование узлов слияния и поглощения создает дополнительные проблемы
при тестировании. Становятся необходимыми тесты синхронизации. Чаще всего
возникают новые проблемы и вопросы, которые следует себе задать.
1. Правильные ли типы транзакций объединились?
2. В случае двух транзакций А и В, которые объединяются (или для А, погло­
щающей В), появляются пять дополнительных ситуаций, которые необхо­
димо протестировать:
* А приходит, а В —никогда не приходит (А).
« В приходит, а А —никогда не приходит (В).
« А приходит раньше В (А, В).
6.3. Отношения и модель 159

* В приходит раньше А (В, А).


« Обе транзакции приходят одновременно (то есть в пределах оговорен­
ного времени) (АВ).
3. Правилен ли тип выходящей транзакции? Для поглощения это хищник, а
для объединения —дочерняя транзакция.
При тестировании необходимо рассмотреть каждый из этих случаев. Для узла
слияния, имеющего три связи, потребуется протестировать 25 возможных вариан­
тов. Для обозначения одновременных входов транзакций в узел слияния мы бу­
дем использовать совместное написание, а для раздельных —запятые. Например,
(АВ, С) означает, что А и В приходят в узел одновременно, а за ними следует С.
Необходимо рассмотреть 25 тестовых вариантов. Ниже следуют тестовые вариан­
ты для поглощения или слияния, в котором участвуют три транзакции.
Каждая транзакция по отдельности: (А), (В), (С).
Две транзакции за раз: (А, В), (А, С), (В, С), (В, А), (С, А), (С, В), (АВ), (АС), (СВ).
Три транзакции за раз: (А, В, С), (В, А, С), (С, А, В), (А, С, В), (В, С, А), (С, В,
А), (А, ВС), (В, АС), (С, АВ), (ВС, А), (АС, В), (АВ, С), (АВС).
Число необходимых тестов быстро возрастает для узлов слияния с нескольки­
ми объединяющимися транзакциями. Проектирование тестов легко автоматизиро­
вать, но трудно заставить транзакции приходить в определенные узлы в определен­
ном порядке. Так как слиянию и поглощению подвергаются чаще всего транзакции,
которые уже прошли через какие-то операции обработки, в отличие от транзакций,
пришедших извне, то выполнение этих тестов практически невозможно.

6.3.5. Циклы
С одной стороны, циклы в потоках транзакций, строго говоря, создают проблемы. А
с другой стороны, они встречаются редко, и если встречаются, то они просты и встре­
чаются нечасто. Цикл, который чаще всего можно обнаружить в потоке транзакций, —
это цикл повторения обработки после обнаружения ошибки ввода данных. Так, на­
пример, банкомат дает вам три попытки ввода вашего личного идентификационного
номера. Можно ожидать, что похожие циклы повторения будут встречаться в боль­
шинстве интерфейсов, таких как каналы связи с другими системами, драйверы уст­
ройств и т. д. Очереди, обслуживаемые как пакет, очевидно, содержат цикл для обра­
ботки пакетов. Сходным образом каждый узел обработки, обслуживающий очередь,
работает в составе цикла для того, чтобы обрабатывать каждый последующий элемент
в очереди и продолжать работу далее. Таким образом, он активируется каждый раз до
тех пор, пока очередь не иссякнет. Такие циклы следует тестировать отдельно для каж­
дого узла обработки на более низком уровне интеграции и тестирования. А это означа­
ет, что необходимо выполнять тестирование циклов различных узлов обработки тран­
закций в контексте компонентного тестирования этих узлов обработки.

6.3.6. Фокус и иерархические модели


Модель потока транзакций можно использовать при различных степенях дета­
лизации, вплоть до кода. Однако создавать модели потока транзакций на уровне
160 Глава б • Тестирование потоков транзакций

исходного кода —отнюдь не самая лучшая идея. Узлы на графах потока транзак­
ций могут представлять собой не только действия программного обеспечения.
Термин «обработка данных» был использован в общем смысле для обозначения
любого вида работы с данными, вне зависимости от того, выполняется ли эта ра­
бота компьютером, людьми или другими системами. Модель потока транзакций
обычно используется как высокоуровневая модель. Наиболее часто ее используют
в системном тестировании. Корректную работу компонентов следует проверить
при компонентном тестировании, обычно это делают на предшествующей стадии
интеграции. Разделение сложного действия на компоненты представляется в мо­
дели потока транзакций лишь выборочно. Но при этом следует учитывать неко­
торые детали.
1. Компоненты модели имеют интерфейсы, через которые происходит переда­
ча данных. Обратите внимание, что глобальные данные могут соответство­
вать этому требованию.
2. Компоненты могут взаимодействать только через свои интерфейсы. Если
есть такие компоненты, сгруппируйте их и моделируйте группу как отде­
льный объект.
3. Поведение компонента определяется типом и состоянием транзакции.
4. Поведение узла обработки не зависит от предыстории транзакции, если
только предыстория не влияет на тип и состояние транзакции. Отдельный
процесс должен быть марковским.
5. Можно проверить корректность поведения узла обработки путем проверки
выходящих транзакций (или их контрольных записей) каждого процесса
в модели.
6. При наличии соответствующих средств тестирования можно полностью
протестировать один компонент в отдельности.
При тестировании потока транзакций первоочередное внимание следует об­
ращать не на корректную работу отдельных процессов, а на систему в целом.
Особенное внимание следует уделять корректности интерфейсов между компо­
нентами, корректности маршрутизации транзакций между компонентами, орга­
низации и дисциплине очередей (если это не правила упорядочения FIFO), узлам
слияния, поглощения, расщепления и порождения, синхронизации, одновремен­
ности, созданию и уничтожению транзакций, а также дублированию и потере
транзакций.

6.4. Методика
6.4.1. Основы
Предположим, что у нас нет циклических транзакций. Если же вы встретите
такие, будем надеяться, что их применение в данном случае является обоснован­
ным, и их можно протестировать в пределах субмодели, включающей цикл. Для
6.4. Методика 161

любых циклов, которые невозможно обработать на более низком уровне, нужно


будет использовать методики тестирования циклов, описанные в главе 4.
1. Проверьте спецификацию.
2. Идентифицируйте и дайте имя всем транзакциям, которые должна обра­
ботать система. У вас не должно возникнуть проблем с «нормальными»
транзакциями, так как они все должны присутствовать в спецификации.
Трудности обычно возникают с транзакциями, которые подразумеваются в
спецификации, но не сделаны явными. Ниже приведены примеры транзак­
ций, которые часто пропущены в спецификациях, но должны присутство­
вать в вашей модели.
• Подтверждения о приеме, уведомление, отрицательное квитирование.
• Специальные транзакции для установки и отладки.
• Специальные транзакции для диагностики действий.
• Транзакции, выполняющие аудит других транзакций.
• Транзакции, используемые в режиме обучения персонала.
• Транзакции инициализации или перенастройки для всех внешних ин­
терфейсов.
• Транзакции, используемые при восстановлении системы.
• Транзакции, используемые для измерения характеристик системы.
• Транзакции, используемые для проверки обеспечения безопасности сис­
темы.
• Транзакции, используемые в протоколах, не упомянутых выше.
• Транзакции, используемые для запроса о статусе других транзакций.
• Ответы на запросы о статусе транзакций.
• Транзакции, создаваемые вашей системой для восстановления других
транзакций.
• Транзакции восстановления, полученные из внешних систем.
3. Определите иерархию типов транзакций, которая включает все транзакции,
описанные выше в пункте 2. Как правило, вы можете использовать ту же ие­
рархию, что и разработчики. Такой подход делает коммуникации проще.
4. Определите состояние транзакции для каждого типа транзакции. Состояния
должны соответствовать последовательности обработки, присущей типу
транзакции. Если состояния представляют собой простую последователь­
ность пунктов, например «шаг 1, шаг 2, шаг 3,... выход», то достаточно будет
просто составить список. Если есть признаки более сложного поведения, то
вам, вероятно, будет необходимо использовать модель с конечным числом
состояний (см. главу 9).
5. Определите поведение транзакции в любой момент ее жизненного цик­
ла. Как она порождается (или поступает в систему), как завершается (или6

6 Зак. 770
162 Глава 6 • Тестирование потоков транзакций

выходит из системы), как происходит операция слияния (и с кем), как пог­


лощается, расщепляется, порождает другую транзакцию и т. д.
6. Определите гипотетическую контрольную запись для каждого из типов
транзакций. Запись должна отображать по меньшей мере тип и состояние
транзакции. При этом в большинстве систем по обработке транзакций вы
должны быть в состоянии использовать действительную контрольную за­
пись транзакции, реализованную в программном обеспечении. Для внешних
транзакций, — таких как, например, транзакции, обрабатываемые другими
системами или людьми, — вам необходимо будет определить подходящую
гипотетическую запись.
7. Идентифицируйте все очереди. Определите для каждой очереди источник
(источники) появления транзакций, правило их упорядочения, приоритеты
в пределах одного правила, а также применяемую обработку. Протестируйте
ограничения всех очередей, которые имеют ограниченные максимально
возможные размеры.
« Каким образом отдельные элементы помещаются в очередь?
* Каким образом отдельные элементы удаляются из очереди?
* Какая модель очереди используется — односерверная или многосервер­
ная? Если многосерверная, каково правило выбора сервера?
8. Идентифицируйте компоненты обработки (это не обязательно должно быть
программное обеспечение). Сгруппируйте компоненты в соответствии с
принципами, описанными выше в разделе 6.3.6. Возможно, потребуется
переопределить типы транзакций, выполнить слияние типов транзакций,
удалить очереди и т. д., если этот этап моделирования приводит к необхо­
димости группировки нескольких компонентов для того, чтобы удовлетво­
рить критериям раздела 6.3.6.
9. Для каждого из определенных на предыдущем этапе компонентов реши­
те, каким образом вы будете тестировать отдельные компоненты. По своей
внутренней структуре каждый компонент может представлять собой дру­
гую — модель потока транзакций более низкого уровня или же модель ино­
го вида.
10. Несмотря на то, что реальные компоненты не обязательно действуют по­
добным способом, отделите расщепления/порождения и слияния/погло-
щения от связанных с ними узлов обработки путем помещения явного узла
расщепления/порождения после обрабатывающего узла и явного узла сли-
яния/поглощения до обрабатывающего узла.
11. После выполнения предыдущих пунктов у вас должен быть набор узлов и
связей, определяющих полный набор потоков транзакций, которые необхо­
димо протестировать.
12. Верифицируйте модель, используя модельную программу, написанную на
удобном языке программирования. Это может оказаться эффективным в
моделях потока транзакций, потому что они чаще всего достаточно велики.
6.4. Методика 163

Типичная система по обработке транзакций содержит много простых транз­


акций. Говоря «много», я подразумеваю «тысячи». Говоря «простые», я под­
разумеваю, что ветвления, соединения, расщепления, порождения, слияния
и поглощения очень редки.
13. Определите пути прохождения ваших тестов. Вы можете использовать как
отдельные пути в графе, так и порожденные подграфы. Действуйте точно
так же, как и при использовании других методик.
14. Активизируйте порожденные подграфы.
15. Предскажите итоги.
16. Определите критерий соответствия.
17. Выполните тесты.
18. Подтвердите итоги.
19. Проверьте значения во всех промежуточных узлах.

6.4.2. Иерархия покрытия


Как и везде, в этой технике тестирования существует набор практических крите­
риев покрытия, от самых простых (наименее трудоемких и неэффективных) до
наиболее эффективных (основательных, но трудоемких).
1. Покрытие ввода/вывода и порождения/завершения. Проведите достаточ­
ное число тестов и убедитесь, что все старты и порождения транзакций
были осуществлены и что были созданы все исходящие транзакции (в том
числе порожденные в данной системе). Эти тесты могут показаться слиш­
ком слабыми, однако многие системы не проходят даже их. Рассмотрите все
типы транзакций, о которых шла речь выше в разделе 6.4.1 (а также те спе­
цифические транзакции, о которых я не говорил, но которые существуют
в вашем приложении). Это тот минимум, который может сделать разум­
ный человек. Исходя из здравого смысла, это эквивалентно гарантии того,
что каждая строка кода была протестирована на уровне компонентов. Если
кто-то полагает, что в тестировании типа транзакций нет необходимости, то
он либо уверен, что транзакция не содержит ошибок, либо считает, что она
вообще не нужна. Если она не нужна, уберите ее, и у вас будет на один ис­
точник ошибок меньше. Наиболее редко используемые транзакции содер­
жат больше всего ошибок. Дурную славу в этом отношении имеют транзак­
ции, связанные с восстановлением.
2. Покрытие узлов. Покрытие узлов само по себе тоже не имеет смысла, по­
скольку оно только еще раз подтверждает выводы, сделанные при тести­
ровании модели более низкого уровня, например, в ходе тестирования
компонентов. Покрытие узлов — это все же лучше, чем ничего, так как мы
убеждаемся, что все порождения, расщепления, слияния, поглощения и об­
работки в очереди транзакции ведут себя корректно. Этой проверки также
могут не пройти многие системы.
164 Глава б • Тестирование потоков транзакций

3. Покрытие связей. Используя тесты, обеспечивающие покрытие связей, мы


проверяем не только корректность отдельных узлов, но и их взаимодей­
ствие друг с другом. Без покрытия связей тестирование системы будет не­
полным. Обеспечивая покрытие связей, мы убеждаемся не только в том, что
все транзакции корректно обрабатываются (покрытие узлов делает это за
нас), но и в том, что на каждом шаге обрабатываются именно те транзакции,
которые и должны.
4. Порожденные подграфы. Понятие порожденного подграфа в этом контексте
практически полностью совпадает с аналогичным понятием для потока дан­
ных (см. главу 5). Если существуют только узлы ветвления и соединения, то
порожденный подграф соответствует пути «вход - выход» в созданной мо­
дели. Если существуют узлы порождения или расщепления, то порожден­
ный подграф получается путем следования но всем связям, исходящим из
узла порождения или расщепления и дальнейшего следования по пути про­
хождения этих транзакций до завершающего узла. Если существуют узлы
слияния или поглощения, то порожденный подграф получается при следо­
вании вдоль входящих связей до точки, где сливающиеся транзакции (или
хищник/жертва) порождаются или входят в систему. Более подробно мы
будем говорить о порожденных подграфах в разделе 6.4.4.

6.4.3. Построение модели


Я бы предпочел построить модель потока транзакций для налоговой декларации,
но, поскольку в процедуре заполнения налоговой декларации отсутствуют транз­
акции, такая модель не подходит. Возможно, лучшим выбором в данном случае
будет модель потока данных. Однако для того, чтобы использовать налоговые
формы в максимально возможном числе упражнений и чтобы показать вам, что
почти любую модель можно использовать в любом приложении, я буду модели­
ровать Employee Business Expense (Бизнес расходы наемного служащего), форма
2106. Я буду рассматривать каждый вход или группу входов так, как если бы они
были транзакциями.
РаГ. Сба Данные об основных расходах наемного служащего обрабатываются
как единая транзакция, состоящая из: строки 2 (p a rk in g , t o l l s
(парковка, подорожныйсбор)). строки 3 ( t r a v e l, e x c lu d in g meals
and e n tertain m en t (командировочные расходы, исключая питание и
развлечения)), строки 4 (o th e r bu sin e ss expenses e x c lu d in g meals
and e n tertain m en t (другие бизнес расходы, исключая питание и
развлечения)), строки 5 (meals and e n tertain m en t (питание и
развлечения)). Это входящая транзакция, то есть транзакция из
узла зарождения.
От 1: С11 General v e h ic le data (Данные об основных транспортных расходах),
в том числе данные из строк 11. 12. 13. 15. 18. 19. 20 и 21.
Транспортных средств может быть более одного, поэтому в этом
стартовом узле может быть от 1 до п маркеров. Для каждого
внесенного транспортного средства нужен один из них.
Фр1: С23 A ctu a l expenses (Фактические расходы), в том числе введенные в
строки 23. 24а. 24Ь и 25. Вам не нужны эти данные, если вы решили
использовать стандартную плату за перевозки. Тем не менее, вы
6.4. Методика 165

можете выбрать фактические расходы. Для этого стартового узла


у вас могут быть значения от нуля до п. Это число может быть
меньше, чем для От 1. но не может быть больше.
Ам 1: СЗО D e p re c ia tio n (Амортизация). Сюда входят данные из строк 30. 31.
33 и 36. Этот стартовый узел не может иметь больше маркеров,
чем Фр1. поскольку вам не обязательно эксплуатировать все ваши
транспортные средства.
Ф1: Ф1а Стартовый узел с незаполненной формой 2106 (за исключением name,
s o c ia l s e c u r it y number, occu p ation (имени, номера социального
страхования и рода деятельности)). Эта форма будет обработана и
отослана обратно, на строку 20 бланка А. где она и возникла.
Ф1а: С1 Ф1а - узел ветвления, в нем делается выбор о будут обрабатываться
транспортные расходы или не будут. (С1) здесь сответствует ветке
НЕТ. Транзакции в форме 2106 могут пойти либо по этой ветке.либо
по ветке Ф1д. не не по двум одновременно.
Ф1Д Это ветка ДА. соответствующая наличию хотя бы одного
транспортного средства.
С 1: Сба С1 - это узел соединения, в который приходит либо транзакция 2106
из узла Ф1а (нет транспортных расходов), либо из узла Т1
(транспортные расходы заполнены).
Сба: СЮ Узел поглощения, в котором поглощаются данные об основных
расходах наемного служащего ( P a l) . Форма 2106 является хищником,
a P a l - жертвой и P a l перестает существовать.
СЮ: Выход (прохождение транзакции обратно в бланк А).
Ф1д: С11а С11а - это узел порождения, где вы даете начало необходимому
числу транзакций: по одной на каждое транспортное средство.
Т1 Место, в котором вы. пройдя форму 2106. ожидаете v e h ic le dedu ction
(налоговых льгот на транспортное средство).
Т1: С1 Т1 - это узел поглощения, в котором налоговые льготы на
транспортное средство вводятся в форму 2106.
Тсум Т1 Тсум - это узел, в котором сливаются данные обо всех транспортных
средствах.
С11а: Тсум

Модель содержит соответствующие пояснительные примечания. С11, С11а


и СЗО — это строки во вспомогательной модели, в которой выполняется большая
часть обработки данных. На уровне нашей модели мы предполагаем, что обработка
выполняется корректно, и ее результат приходит в узел Тсум. Вам предлагается раз­
работать более детальную модель этой обработки в упражнении 2. После того как
вы разработаете модель потока транзакций для обработки, вы, надеюсь, согласитесь
со мной, что в данном случае уместнее было бы использовать модель потока данных,
или модель потока управления. Выбранный мной способ разбиения на части дан­
ной модели был удобен для меня, и он в точности повторяет структуру форм, пред­
ложенную ВНС. У вас может быть свое собственное мнение на этот счет, и оно при­
ведет к другому, но не менее эффективному разбиению проблемы на части.

6.4.4. Выбор путей и/или порожденных


подграфов тестирования
Следует рассмотреть несколько ситуаций, зависящих от того, есть ли в иссле­
дуемой модели узлы порождения/расщепления и/или слияния/поглощения.
В любом случае мы предполагаем, что у нас нет циклов или что циклы могут
166 Глава 6 • Тестирование потоков транзакций

присутствовать во вспомогательных моделях. Поскольку модели потоков тран­


закций, как правило, состоят из множества маленьких независимых субмоделей,
то, скорее всего, даже если вы решите использовать модель потока транзакций,
может оказаться, что некоторые из субмоделей лучше описываются при помощи
модели потока данных или модели потока управления. Ниже приведены некото­
рые наиболее часто встречающиеся случаи:
1. Чистая модель потока управления, есть только ветвления и соединения.
2. Узлы слияния и поглощения, нет ветвлений, нет соединений.
3. Узлы слияния и поглощения с ветвлениями и соединениями.
4. Управляющие потоки с расщеплениями и порождениями, но без слияний и
поглощений.
5. Общий случай.
Случай 1: Чистая модель потока управления
Этот случай полностью идентичен случаю тестирования потока управления. Если
все потоки транзакций подобны потокам управления, то лучше выбрать модель
потоков управления. По сравнению с моделями потоков управления модели по­
токов транзакций имеют три отличия.
1. Обычно приходится рассматривать много потоков транзакций, несмотря на
то, что все они относительно простые.
2. Большая вероятность существования моделей с числом входов и выхо­
дов, отличным от единицы. Транзакции могут приходить из разных источ­
ников и вследствие этого помещаться в различные очереди на обработку.
Транзакции могут направляться в различные точки назначения и вследс­
твие этого помещаться в различные выходные очереди. Нам недостаточно
убедиться в корректности обработки транзакций, необходимо также прове­
рить, что транзакции прошли правильным маршрутом. В принципе вас не
должно удовлетворять простое покрытие связей, вы должны обеспечить та­
кое покрытие для всех имеющих смысл комбинаций «вход - выход».
3. Кроме того, вам еще надо рассмотреть и проверить правила упорядочения в
очередях.
Случай 2: Узлы слияния и поглощения,
нет ветвления, нет соединения
Как обсуждалось в главе 5, разделе 5.4.4, это случай чистой модели потока дан­
ных. Вы можете создать порожденный подграф для каждого возможного выхо­
да. Вы начинаете его строить из выходного узла и идете в обратном направлении
к стартовым узлу(ам) для данного выхода. Включите все обратные ветвления, по­
скольку все они вносят свой вклад в обработку данных. В нашем примере, строя
порожденный подграф, идущий назад из СЮ, мы придем в Сба. Затем мы должны
включить в него связь из узла С1 (и все, что в него входит) и связь из P a l, поскольку
обе связи поставляют в Сба данные, необходимые для обработки.
6.4. Методика 167

Случай 3: Узлы слияния и поглощения


с ветвлением и соединением
В этом случае порождения и расщепления отсутствуют. Несколько транзакций
входят в модель, и меньшее их число выходит. Остальные транзакции поглощают­
ся в процессе прохождения модели. Этот случай идентичен случаю 3 раздела 5.4.4
главы 5. Если вы прочли эту главу, то вам надо прочесть то, что относится к данно­
му случаю еще раз, и интерпретировать его на языке потоков транзакций. Если вы
не читали про этот случай, то прочитайте, игнорируя все, что касается узлов вы­
бора. Убедитесь, что вы, по крайней мере, охватили достаточное количество путей,
чтобы обеспечить покрытие связей.
Вы создаете порожденный подграф так же, как в предыдущем случае, за исклю­
чением того, что после узлов соединения вы должны следовать по обеим входя­
щим в этот узел соединения связям, чтобы убедиться, что вы включили в порож­
денный подграф все источники данных. Этот порожденный подграф определяет
набор тестовых вариантов.
Рассмотрим существующие в модели узлы ветвления. Каждое значение пара­
метра, управляющего ветвлением, определяет выбор одного из альтернативных
путей. Выберите один из них. Теперь некоторые входные транзакции уже не нуж­
ны, следовательно, их можно убрать. Продолжайте этот процесс до тех пор, пока
у вас не останется только один определенный путь (и соответствующие входные
транзакции). Проделайте это еще раз, выбрав другую ветвь для другого варианта
тестового варианта. Перебор следует продолжать до тех пор, пока вы не обеспечи­
те покрытия связей.
Случай 4: Управляющие потоки с расщеплениями
и порождениями, но без слияний и поглощений
Это достаточно простой случай. Начните с выхода и сделайте порожденный под­
граф для каждой транзакции, приходящей в выходные узлы. Сделайте один по­
рожденный подграф (от выхода до всех стартовых узлов, имеющих к нему отно­
шение) для каждой выходной транзакции. Поделите этот порожденный подграф
на более мелкие части (больше тестовых вариантов), чтобы обеспечить покрытие
связей для узлов ветвления.
Случай 5: Общий случай
В данном случае не существует простых рецептов. Общая идея состоит в том, что­
бы сделать порожденный подграф для каждой выходной транзакции. Включите
в него все входные транзакции, обеспечивающие данные. Если в каком-либо из
этих порожденных подграфов существуют управляющие потоки, убедитесь, что
вы разделили их и получили дополнительные тестовые варианты, гарантирую­
щие покрытие связей в каждом из порожденных подграфов. Может показаться,
что мы создаем избыточные тестовые варианты, поскольку порожденные подгра­
фы перекрываются, — и, обеспечив покрытие связей для транзакции типа А, мы
можем проделать это заново для транзакции типа В (в другом порожденном под­
графе, включающем в себя некоторые ветви из предыдущего порожденного под­
графа). Для мотивировки этого, казалось бы, избыточного действия достаточно
168 Глава 6 • Тестирование потоков транзакций

задать себе вопрос: «Что является целью тестирования»?» Я уже ранее говорил,
что системное тестирование —это не проверка работы отдельных узлов, а провер­
ка того, правильно ли транзакции проходят от обработки к обработке. Поскольку
большая часть обработки (в случае потоков транзакций) включает в себя услов­
ные ветви, которые частично зависят от типа транзакций, то не лишним будет про­
верить одну и ту же логику для различных типов транзакций. По сути, такое «из­
быточное» покрытие связей может оказаться единственным способом проверить
глубоко скрытые составные предикаты.
Используя данные выше рекомендации, мы получаем два семейства тестов.
С10/Сба/p a l . С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, очевидно, короче, чем путь, лежащий через процедуру обработки транспортно­
го средства (от С 11а до Тсум). Таким образом, я могу сделать вывод, что транзак­
ция формы 2106 всегда приходит в узел Т1 раньше, чем данные о транспортном
средстве, и ждет их там. Значит, у нас есть только 2 варианта для рассмотрения.
Либо форма 2106 приходит раньше данных о транспортном средстве, либо данные
о транспортном средстве отсутствуют».
Если вы и в самом деле так считаете, то делаете ошибочное допущение и попа­
дете в ту же ловушку, что и программисты, создавшие программу, которую вы тес­
тируете. Это всё рациональные приближения, однако природа ошибок не рацио­
нальна. К тому же обе связи, входящие в Т1, могли бы представлять собой очереди
(в данном примере это не так), и правило упорядочения может вызывать любые
перестановки.
Если вы не можете с уверенностью сказать, что возможен лишь один опреде­
ленный порядок (например, форма 2106 приходит раньше данных о транспортном
средстве), то вам будет лучше проверить все случаи. Система должна вести себя
разумно для всех случаев. Я подразумеваю, что она не уничтожает, не изменяет и
не теряет данные, а неполные транзакции она отвергает, уведомляя об этом поль­
зователя или иную систему, породившую транзакцию.
Насколько глубоко мы должны проверять синхронизацию? Должны ли мы
учитывать взаимодействие одного узла слияния с другим, находящимся ниже
6.4. Методика 169

в исследуемом порожденном подграфе? Гипотетически —да, но на самом деле не


стоит этого делать. Число тестов растет экспоненциально, а продуктивность таких
тестов синхронизации высокого порядка совсем не очевидна. Более того, проведе­
ние тестов для одного слияния уже является непростой задачей, проверка же по­
следовательности слияний может оказаться невозможной.
А что, если один и тот же узел слияния встречается в нескольких порожденных
подграфах? Следует ли повторять тесты синхронизации в каждом из них? Скорее
всего, не следует, и главным образом потому, что это приведет к быстрому росту
числа тестовых вариантов. Но есть и другая причина. Вы, возможно, сможете про­
верить эти случаи быстрее и с меньшими усилиями путем автоматической генера­
ции соответствующим образом подобранных случайных тестовых вариантов.

6.4.6. Тестирование очереди


Проверка любой, не слишком простой очереди требует применения целой груп­
пы тестов. Где это следует делать, в системном тестировании или на более низком
уровне компонентного тестирования? Если узел имеет только одну входящую
связь, и у меня есть причины считать, что этой очередью управляет представля­
емый этим узлом компонент, то я отдаю предпочтение тестированию очереди в
контексте компонентного тестирования. Если узел является узлом слияния, по­
глощения или соединения (несколько входящих связей), то я буду должен прове­
рить очередь на уровне компонентов, а затем повторить эти тесты при тестирова­
нии системы. Какие именно тесты вам нужны, зависит от правила упорядочения
и правила выбора сервера, если он есть. Ниже приводятся некоторые полезные
виды тестов.
1. Тестирование пределов длины очереди.
* Максимальная длина очереди. Попытайтесь превысить предельно до­
пустимое число элементов в очереди.
* Пустая очередь. Активизируйте обработку, когда в очереди ничего нет.
* Проверка циклов. Узел, обрабатывающий очередь, содержит цикл для
обработки элементов очереди (особенно это касается групповых серве­
ров). Используйте методы тестирования циклов для нескольких элемен­
тов в очереди.
* Динамические изменения длины очереди. Попытка добавить транзак­
цию в очередь (особенно в очередь пакетной обработки) во время прове­
дения обработки элементов является, очевидно, необходимым тестовым
вариантом. Кроме этого, попробуйте удалить элемент из очереди, пока
обработчик очереди активен, если система обработки это вам позволит.
2. Тестирование сортировки и выбора. Часто правила упорядочения включа­
ют в себя процедуру сортировки. Например, правило может указывать, что в
первую очередь обрабатываются наиболее старые транзакции. Это правило
отличается от правила построения очереди FIFO (First in First Out —первым
прибыл, первым обслужен). Очередь FIFO строится на основе положения
170 Глава 6 • Тестирование потоков транзакций

элемента в очереди. За основу в правиле «старейшая транзакция обрабаты­


вается первой» берется отметка времени в контрольной записи транзакции.
Поскольку транзакции проходят различные пути до того, как становятся в
данную очередь, порядок FIFO может отличаться от порядка отметок вре­
мени. Другой пример — это очереди с приоритетом, в которых существует
внутренняя сортировка по степени приоритета. Обработка должна включать
в себя явную процедуру сортировки или, если очередь не слишком длинная,
может осуществляться сканирование всей очереди, чтобы выбрать следую­
щий элемент для обработки. Оба этих варианта представляют собой неяв­
ную процедуру сортировки. Сортировка всегда происходит на основе реаль­
ного или скрытого ключа. Существуют элегантные способы тестирования
процедур сортировки, но они лежат за рамками данной книги. Мы ограни­
чимся некоторыми простыми, но эффективными эвристическими методами.
Ниже приведено несколько случаев, которые стоит проверить.
* Правильное упорядочение.
« Все элементы имеют одинаковые ключи сортировки.
« Элементы располагаются в обратном порядке.
« Присутствует только один элемент в очереди. Проверьте все дискретные
ключи сортировки (то есть приоритеты).
« Один элемент для каждого дискретного ключа сортировки.
* Для многоуровневых ключей (например, возраст внутри одного приори­
тета) рассмотрите комбинации приведенных выше тестов в контексте
тестирования вложенных циклов.
3. Тестирование упорядочения очереди. Если в вашем случае правило упоря­
дочения отличается от FIFO, вы должны провести тестирование упорядо­
чения очереди, чтобы убедиться, что оно было реализовано корректно. Если
это правило определяется неявной сортировкой (например, приоритетом),
то используйте описанные выше тесты. За исключением этого, дать общие
рекомендации довольно трудно, поскольку правила упорядочения могут
быть самыми разными.
4. Тестирование приоритетов. Следует различать многоуровневые приорите­
ты в одной очереди и отдельную очередь для каждого приоритета. В первом
случае тестирование представляет собой проверку сортировки, основанной
на приоритетах. Во втором случае необходимы некоторые дополнительные
тесты:
* Существует только один приоритет. Рассмотреть этот случай для каждо­
го приоритета.
* Присутствуют все приоритеты, берется по одному элементу на каждый
приоритет.
« Присутствуют все приоритеты, берется несколько элементов на каждый
приоритет.
Методика 171

* Приоритеты меняются во время обработки (если это позволяет прило­


жение). Протестируйте случаи повышения и понижения приоритета.
Очереди по приоритету заслуживают особого внимания, особенно если суще­
ствуют другие ключи, используемые в других процессах. Например, пусть в одной
очереди ключ определяется в области значений, а в другой очереди ключ пред­
ставляет собой степень секретности. Для ключевых значений сначала обрабаты­
ваются транзакции, соответствующие наибольшим значениям, затем меньшим, и
так далее. В очереди, упорядоченной по степени безопасности, первыми обрабаты­
ваются совершенно секретные транзакции, затем просто секретные, затем довери­
тельные и так далее. Обе очереди являются очередями по приоритету, поскольку,
хотя одно поле и называется «значение», а другое «степень секретности», поведе­
ние элементов в обеих очередях определяется приоритетом. О чем тогда беспоко­
иться? Все дело в том, что при возникновении подобной ситуации программист
с большой вероятностью перепутает две очереди и использует неверный ключ.
В моей практике я видел, как «конфиденциальность» путали с «безопасностью»
и оба эти понятия путали с «приоритетом».
5. Тестирование правила выбора сервера. Проверяйте множественные серве­
ры с одной очередью путем низкоуровневого компонентного тестирования.
Если у вас есть несколько очередей, которые служат входными связями во
множественный сервер, то правило выбора сервера должно быть провере­
но (или хотя бы перепроверено) при тестировании системы. Тестирование
правила выбора сервера напоминает тестирование сортировки, и выпол­
нять его надо очень тщательно при помощи следующих вариантов:
» Все элементы в одной очереди.
» Во всех очередях один элемент.
* Во всех очередях одинаковое число элементов.

6.4.7. Активизация
Проблема активизации при тестировании потоков транзакций отличается от ана­
логичной проблемы в методах тестирования потоков управления или потоков дан­
ных. Задача заключается не в том, чтобы найти такие транзакции, которые просле­
дуют по выбранному пути. На самом деле суть проблемы — создать транзакции,
выполняющие это условие, и ввести эти транзакции в систему. Хотя обычные
транзакции, как правило, не слишком сложны, типы транзакций, представленные
в разделе 6.4.1, иногда бывает просто невозможно ввести. Ниже приведены неко­
торые характерные проблемы и возможные способы их решения.
1. Ошибки, отрицательное квитирование и восстанавливающие транзакции из
других систем. Это было моим проклятием. Вы не можете получить эти тран­
закции, не заставив другую систему вести себя неправильно. Вам необходи­
ма транзакция из другой системы, информирующая вас, что один из ваших
блоков данных был утерян или искажен. Однако вы не можете послать ей
блок данных или искаженный блок, поскольку такие ошибки могут быть об-
172 Глава 6 • Тестирование потоков транзакций

наружены промежуточными системами. Вам придется заставить другую сис­


тему послать вам сообщение об ошибке, хотя на самом деле ошибки не было.
Вы пытаетесь наладить сотрудничество, но в ответ вам с пафосом заявляют:
«Наша система никогда не посылает сообщения об ошибках!» Вы пытаетесь
как-то решить эту проблему, а заканчивается все тем, что вы объясняете раз­
гневанному чиновнику в полосатом костюме из государственного департа­
мента в Вашингтоне, что не собирались раздуть международный скандал1. На
этот случай я не знаю приемлемого технического решения, поскольку это не
техническая проблема. В крайнем случае вам придется построить имитаторы
всех таких недружественных интерфейсов и протестировать все случаи, ис­
пользуя эти имитаторы. А потом остается только надеяться на лучшее.
2. Внутренние транзакции, связанные с восстановлением системы и нелогич­
ными условиями. Система должна иметь защиту от аварий, таких как от­
казы программного или аппаратного обеспечения. Вы не сможете протес­
тировать защитные механизмы, не создав в точности такую же ситуацию,
против которой система должна себя защищать. Следует точно узнать, при­
нимаются ли необходимые меры по защите. Вы должны сломать доктрину
безопасности. Проверить, предусмотрено ли в вашем случае аварийное вос­
становление состояния системы и данных. Вы должны имитировать все ме­
ханизмы аварий и порождаемые ими транзакции.
3. Внутренние транзакции для восстановления данных и нелогичных усло­
вий. Если система обнаруживает потерянные или дублированные транзак­
ции, то и тестировщик должен иметь возможность терять или дублировать
транзакции. Любой механизм восстановления данных рассчитан на опре­
деленный сценарий их потери или искажения. Вы должны воспроизвести
каждый такой сценарий для соответствующих транзакций.
На практике задача активизации заключается в том, чтобы правильно генериро­
вать и внедрить необходимые вам для проверки системы транзакции. Единственный
разумный способ это сделать —это встроить в систему генератор транзакций на ран­
ней стадии проектирования. Минимум действий, которые должен уметь выполнять
встроенный генератор транзакций, выглядит следующим образом.
1. Создание любых заданных транзакций, как корректных, так и некорректных.
2. Размещение эти транзакций в любом месте заданной очереди.
3. Удаление выбранных транзакций из очереди.

6.4.8. Предсказание итогов


Нашей задачей при проведении тестирования не является детальная проверка
данных в транзакциях. Цель системного тестирования (в контексте модели потока
транзакций) заключается в проверке корректного прохождения транзакций, в том
числе их порождения, завершения и так далее. Ожидаемым итогом в этом случае

Это реальный факт из моей практики.


6.4. Методика 173

является определение того, какие транзакции в каких очередях должны находить­


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

6.4.9. Проверка соответствия пути


На самом деле если существуют слияния или порождения, то это будет провер­
кой соответствия порожденного подграфа. Проблема заключается не в том, чтобы
убедиться в правильности пути, а в том, чтобы найти способ встроить в систему
инструменты, которые это будут делать. Существует два основных источника не­
обходимых данных, и в обоих случаях вам, возможно, придется создавать доста­
точно продуманную программу, поскольку вероятность того, что в универсальных
инструментах предусмотрены все возможности ваших транзакций, весьма мала.
1. Существующие записи. Системы обработки транзакций обычно включают
в себя запись активности транзакций, которая требуется в различных при­
ложениях. Например, информацию о счетах, журнал безопасности, резерв­
ные и архивные данные. Эти данные записываются в узлах, которые чаще
всего и являются целью тестировщика. Например, в системах восстанов­
ления данных обычной практикой является запись состава всех активных
очередей. Прежде чем вы потребуете расширить возможности регистрации
данных в системе, исследуйте все журналы регистрации и записи, необхо­
димые в приложении, и подумайте, могут ли эти данные помочь вам прове­
рить исследуемый путь.
2. Встроенная регистрация. Обсуждаемое в предыдущем пункте дополнение
данных, предоставляемых приложением, необходимо для устранения бе­
лых пятен. Постарайтесь ограничиться минимальными добавлениями, что­
бы дополнительная регистрация данных не влияла существенно на поведе­
ние системы. Как правило, это вполне реально осуществить, и часто объем
ресурсов, достаточный для проведения самой полной регистрации транзак­
ций не превышает нескольких процентов от общего объема доступных ре­
сурсов. Как правило, такие возможности регистрации должны встраиваться
сразу, поскольку сделать это задним числом будет очень сложно.
3. Действия в режиме трассировки. Это наиболее приятный способ регистра­
ции. Транзакции вполне могут запускаться в режиме трассировки. Это озна­
чает, что производится постоянная запись всех процессов, в которых участ­
вовали эти транзакции, и всех очередей, в которых они стояли. Разумеется,
такая возможность тоже должна быть встроена в систему. Вне зависимости
174 Глава 6 • Тестирование потоков транзакций

от того, насколько важен режим трассировки для тестировщика, он вполне


оправданно считается отличным инструментом для отладки системы.

6.5. Рассмотрение приложений


6.5.1. Индикаторы приложений
Насколько хорошо вы сможете описать поведение системы при таком моделиро­
вании? Критериями применимости данного метода могут служить положитель­
ные ответы на приведенные ниже вопросы.
1. Выполняется ли работа дискретными единицами?
2. Распределяются ли единицы работы между обрабатывающими модулями
при помощи очередей или подобных интерфейсов?
3. Существуют ли в вашем случае множественные серверы?
4. Выполняются ли ваши процессы квазипараллельно?
5. Существует ли между процессами связь в виде сообщений?

6.5.2. Предположения об ошибках


Основное предположение должно быть следующим —каждый отдельный процесс
работает корректно (был проверен со всех сторон на более ранней стадии инте­
грации), а ошибки, которые мы ищем, возникают вследствие некорректной реа­
лизации связи между компонентами или как побочный эффект многозадачности.
Типичный список предположений об ошибках включает в себя несколько стан­
дартных пунктов.
1. Некорректные очереди. Пропуск очередей, лишние очереди, неправильные
типы очередей.
2. Некорректные порождения или расщепления. Система использует порож­
дения транзакций неправильного типа, неверный порождающий элемент,
создание копий.
3. Некорректные слияния или поглощения. Неправильные слияния или по­
глощения, потери.
4. Ошибки маршрутизации очереди. Соединение выходов с неверными вход­
ными очередями.
5. Ошибки в правилах упорядочения. Действует неверное правило упорядо­
чения.

6.5.3. Ограничения и предостережения


Мы предполагаем, что наш проект обладает правильным дизайном. Он имеет ие­
рархическую структуру, в нем существует ясное разделение между обработкой
6.5. Рассмотрение приложений 175

данных и управлением очередями, транзакции однозначно делятся на типы, осу­


ществляется явная запись управления транзакциями, и маршрутизация транзак­
ций производится централизованно. Чем лучше проект, тем легче будет обеспечить
полное покрытие при помощи тестирования потоков транзакций. Это означа­
ет, что тестировщик сможет сделать обоснованные предсказания (проведя соот­
ветствующие тесты) о пригодности программы к использованию. Предположим
теперь, что у вас плохой проект. Значит ли это, что тестирование потоков транз­
акций будет бесполезно? Нет, оно все равно будет очень полезно. Обсуждаемые
здесь тесты легко сломают программу, основанную на плохом проектировании.
Единственное, что вы не сможете сделать для плохого проекта, —это статистичес­
ки оправданно предсказать его пригодность к использованию.
Единственное важное ограничение для этой модели —это требование марков­
ского поведения от каждого узла. В случае немарковского поведения у вас не бу­
дет другого выбора, кроме как тестировать каждый возможный путь для каждой
возможной транзакции, поскольку поведение будет зависеть не только от данных,
содержащихся в транзакции, но и от предыстории ее поведения. Такое тестирова­
ние редко осуществимо на практике. Сколько-нибудь разумное понятие покры­
тия бесполезно при отсутствии марковского поведения. Если у вас случай именно
такого поведения и вы выполните предложенные здесь тесты, то ничего не добье­
тесь, кроме ошибочной уверенности. Немарковское поведение может быть сколь
угодно сложным, поэтому любое выполняемое вами покрытие охватит лишь не­
большую часть возможных вариантов. Что вам следует делать при встрече с не­
марковским поведением?
1. Избавиться от него путем перепроектирования. В любом случае это лучший
выбор. В большинстве случаев можно обойтись без немарковского поведе­
ния. Оно возникает, когда люди недостаточно хорошо разобрались в вопро­
се.
2. Изолировать его. Вам, возможно, придется это сделать, если ваша модель
описывает поведение человека или поведение других, не контролируемых
вами систем. Процедура изоляции может заключаться в наложении ограни­
чений на действия (изменение спецификации) или выделении подобного
поведения в отдельную субмодель, которую вам придется проверить очень
тщательно, прежде чем вы перейдете к тестированию системы более высо­
кого уровня.
3. Смириться с риском. Иногда это допустимо. То, что приемлемо в развле­
кательных программах, не может быть приемлемо в жизненно важном про­
граммном обеспечении.

6.5.4. Автоматизация и инструментальные средства


Рассмотрим отдельно автоматизацию выполнения тестов и автоматизацию их
проектирования.
1. Автоматизация выполнения тестов. Необходимость автоматизации вы­
полнения частично была рассмотрена выше в разделах 6.4.7-6.4.Э. Что ка­
176 Глава 6 • Тестирование потоков транзакций

сается коммерчески доступных инструментов тестирования, то системы


покрытия/воспроизведения и языки подготовки сценариев являются на­
иболее подходящими инструментами для автоматизации выполнения тес­
тов. Однако в большинстве систем разработки, о которых стоило бы гово­
рить, наличие встроенных средств тестирования —обязательное условие.
2. Автоматизация разработки тестов. Системы автоматизации могут варьиро­
ваться от тривиальных до сложнейших. Языки и системы, предназначенные
для создания генераторов тестов, широко распространены (как коммерче­
ские, так и частные). Имеет смысл потратить пять лет работы, чтобы создать
специализированный генератор автоматического тестирования транзакций
для проекта, разработка которого потребует 100 лет общих трудозатрат.
Хотя здесь редко встречаются непреодолимые технические трудности, я до­
пускаю, что может быть достаточно трудно убедить нужных людей, что инс­
трументы тестирования подобного рода стоят потраченных на них времени
и сил.

6.6. Резюме
Модель потока транзакций является эффективной моделью, применяемой
в высокоуровневом системном тестировании большого количества систем.
Моделирование начинается с идентификации интересующих нас транзакций, осо­
бенно мест, где они порождаются и завершаются и обстоятельств, при которых это
происходит. Модель основана на допущении о марковском процессе1. В ней так
же предполагается, что подробные модели обработки были созданы и использова­
лись на более низком уровне компонентного тестирования, на стадии, предшест­
вующей интеграции. Основное внимание при тестировании потоков транзакций
уделяется очередям, и маршрутам транзакций в системе. Мы рассмотрели эври­
стическую иерархию покрытия, основанную на порожденном подграфе.

6.7. Вопросы для самопроверки


1. Дайте определение ( в контексте тестирования потоков транзакций ) следу­
ющих терминов: узел поглощения, обслуживание пакета, покрытие порож-
дения/завершения, стартовый узел, ограниченная очередь, узел ветвления,
предикат ветвления, управляющая входящая связь, дочерняя транзакция,
узел завершения, FCFS, FIFO, узел соединения, LCFS, LIFO, покрытие
связей, маркировка, марковский узел, марковский потоковый граф, узел
слияния, материнская транзакция, множественный сервер, очередь, покры­
тие узлов, покрытие зарождения/выхода, узел зарождения, родительская

1 Иными слонами полагают, что поток транзакций является марковским процессом (процессом
без последействия), в котором будущее поведение транзакции зависит только от текущего состояния
и не зависит от предыстории процесса. — Примеч. научи, ред.
6.7. Вопросы для самопроверки 177

транзакция, транзакция - хищник, транзакция - жертва, очередь по при­


оритету, тестирование приоритетов, правило упорядочения, тестирование
правила упорядочения, тесты очереди, случайное обслуживание, правило
выбора сервера, односерверная очередь, порожденный подграф, тестирова­
ние сортировки, узел расщепления, тесты синхронизации, задача, действия
в режиме трассировки, транзакция, узел ветвления транзакции, предикат
ветвления транзакции, управляющая запись транзакции, узел соединения
транзакций, регистрация транзакций, тестирование выбора транзакции, со­
стояние транзакции, маркер транзакции, тип транзакции.
2. Разработайте подробную модель части формы 2106, связанной с расхода­
ми на транспортные средства. Считайте, что число транспортных средств
ограничено п. Вводя соответствующие данные для каждого транспортного
средства (0т1, Фр1, Ам1, С11а) имейте в виду, что вы можете вводить фактичес­
кие расходы и амортизацию, только если вы являетесь владельцем транс­
портного средства; однако вы не обязаны декларировать фактические рас­
ходы. Если же вы это делаете, то не обязаны декларировать амортизацию.
Считайте, что вы нашли способ получить максимальные льготы (выбрав
между стандартными и фактическими льготами). Введите в эту субмодель
данные для всех транспортных средств и получите одно число общих льгот
на транспортные средства (Тсум). Разработайте модель, выберите пути, акти­
визируйте их, определите, что вы хотите проверить, исследуйте синхрони­
зацию для слияния транзакций, и так далее. Проводите только чистые тес­
ты.
3. Разработайте грязные тесты для задачи 2. Рассмотрите потерю, дублирова­
ние, искажение данных о транспортном средстве. Учтите, что вы не можете
декларировать фактические расходы для одного транспортного средства, а
амортизацию для другого. Все данные о транспортном средстве (0т1, Фр1, Ам1)
должны являться частью соответствующего набора для данного транспорт­
ного средства.
4. Для проверки слияния двух транзакций необходимо пять контрольных тес­
тов, в случае трех транзакций таких тестов должно быть уже 25. Сколько
тестовых вариантов потребует проверка слияния четырех транзакций?
А сколько потребует слияние п транзакций?
5. Разработайте модель потока транзакций для формы 1040: (а) строки 7-22,
(б) строки 23-30, (в) строки 32-40, (г) строки 41-45, (д) строки 47-53,
(е) строки 45-60. В каждом случае считайте, что все входные значения вво­
дятся в виде единой транзакции, возможно, из предыдущего блока строк.
Моделируйте эти вычисления как единый элемент обработки, который
не надо тестировать. Рассматривайте каждую встречающуюся форму или
бланк как транзакции, которые могут порождаться и/или поглощаться как
положено. Включите в модель логику для определения того, нужны или не
нужны в ней данные формы. Например, в строке 14 в случае существования
«дополнительных доходов» будет создана форма 4797, которая потом будет
возвращена заполненной соответствующим образом и поглощена формой
178 Глава 6 • Тестирование потоков транзакций

1040, то же самое будет с W2, бланком В, бланком С, формой 3903 и так да­
лее. Не пытайтесь моделировать эти формы. Создавайте пустые формы, как
того требует логика, отправляйте их на соответствующий узел обработки
форм, затем принимайте данные формы обратно в соответствующие строки
формы 1040. Разработайте следующие типы тестов: покрытие узлов, покры­
тие связей, покрытие порождения/завершения.
6. Выполните задачу 5 в предположении, что вспомогательные формы могут
быть сначала открыты, а затем оставлены незаполненными, поскольку ока­
залось, что в них нет необходимости.
7. Выполните еще раз задачу 5 в предположении, что различные строки могут
заполняться в произвольном порядке при условии, что существуют требу­
емые данные (то есть вы не можете добавлять числа, пока они не введены).
Разработайте необходимые тесты синхронизации, считая, что входящие
формы поступают по очереди, но в произвольном порядке.
Тестирование
доменов

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

7.2. Основные термины


Внешние термины: алгебра, неоднозначный, приложение, аппроксимировать, мас­
сив, вычислять, оператор CASE, классификация, код, коэффициент, коллинеарный,
константа, несовместимый, координатные оси, компланарный, проверка соответ­
ствия данных, размерность, уравнение, эквидистантный, выражение, ЛОЖЬ,
функция, иерархия, IF-THEN-ELSE, реализация, неравенство, пересекаться, линия,
линейный, логика, сопровождение, означать, модель, нелинейный, численный, пе­
рекрывать, параллельный, плоскость, точка, полиномиальный, точность, обработ­
ка, программа, программист, радиус, область, округление, набор, программное обес­
печение, пространство, подмножество, поверхность, символическая подстановка,
система, таблица, управляемый таблицами, тестируемость, преобразование, дерево,

Внутренние термины: слепота, ошибка, случайная корректность, поток управ­


ления, поток данных, граф, ввод, связь, покрытие связей, вес связи, объект, итог,
узел, покрытие узлов, вес узла, вывод, предикат, отношение, спецификация, тест,
тестовый вариант, поток транзакций.
Входная