Тестирование-книга. Ю. Н. Артеменко Научный редактор
Скачать 6.27 Mb.
|
Глава 7: Разработка тестов 1 8 1 портами и конфигурированием жесткого диска не забудьте сделать его р е зервную копию. Для каждого поля ввода данных выполните следующее: 1. Проанализируйте значения, которые в него м о ж н о вводить. Сгруппируйте их в классы. 2. Проанализируйте возможные граничные условия. Их м о ж н о описать, ис ходя из определений классов, но возможно, что в ходе этого анализа добавятся и новые классы значений. 3. Нарисуйте таблицу, в которой перечислите все классы значений для к а ж дого поля ввода и все интересные тестовые примеры (граничные и дру гие особые значения). Пример такой таблицы приведен на рис. 7 . 1 . Если у вас будет плохо получаться, прочитайте раздел главы 12 "Таблицы гра ничных значений". 4. Протестируйте программу, используя записанные значения (а если их слишком много, то некоторое их подмножество). Протестировать про грамму, означает не только запустить е е , ввести данные и посмотреть, не произойдет ли сбой, — важно, чтобы программа правильно исполь зовала введенные данные. Получаются ли, например, при печати указан ные пользователем отступы? Обязательно придумайте тестовую процедуру, в которой программа использует введенную вами информацию. Обзор Эта глава начинается с анализа характеристик хорошего набора тестов. В ней описываются пять технологий: • Анализ классов эквивалентности. • Анализ граничных условий. • Тестирование переходов м е ж д у состояниями. • Тестирование ситуаций гонок и других аспектов работы программы, за висящих от времени. • Прогнозирование ошибок. Из данной главы вам предстоит узнать о группе исключительно эффективных технологий, называемых тестированием функциональной эквивалентности. В ней описывается методика проведения регрессионного тестирования — неотъем лемой части любого процесса разработки программного обеспечения. В завершение рассказа о разработке эффективных тестов приведены несколь ко замечаний по поводу их выполнения. Иногда у тестировщиков имеются прекрасные идеи, но не доведенные до логического завершения или плохо реализованные, они не выполняют своей задачи, и ошибки остаются ненай денными. В этой работе существует несколько ловушек, о которых следу ет знать. Библиография О вопросах, освещаемых в этой главе, подробно рассказывается у М а й е р - са (Myers, 1979) — особенно хорошо он пишет о классах и граничных ус- 1 8 2 Часть II: Приемы и технологии тестирования ловиях. О различных технологиях тестирования "черного ящика" можно про читать в любой из книг Майерса, Данна (Dunn), Хезела (Hetzel), Бейзера (Beizer) или Эванса (Evans). Некоторая полезная информация в понятном изложении имеется и у Йордана (Yourdon, 1975). Можно разработать миллионы и триллионы тестов — было бы только время. К сожалению, его хватает от силы на несколько сотен или тысяч тестов. Поэтому выбирать приходится тщательно. Характеристики хорошего теста Хороший тест должен удовлетворять следующим критериям: • Существует обоснованная вероятность выявления тестом ошибки. • Набор тестов не должен быть избыточным. • Тест должен быть наилучшим в своей категории. • Он не должен быть слишком простым или слишком сложным. Обоснованная вероятность выявления ошибки Целью тестирования является поиск ошибок. Поэтому, придумывая тестовые примеры, проанализируйте все возможные варианты сбоя про граммы или ее неправильного поведения. Если в программе может про изойти определенная ошибка, подумайте, как ее поймать. Хорошим источником идей о возможных ошибках программ может послужить при ложение этой книги. Набор тестов не должен быть избыточным Если два теста предназначены для выявления одной и той же ошибки, зачем выполнять их оба? Тест должен быть лучшим в своей категории В группе похожих тестов одни могут быть эффективнее других. Поэто му, выбирая тест, нужно взять тот, который с наибольшей вероятностью выявит ошибку. В первой главе уже рассказывалось о том, что на границах каждого диапазона значений параметров программ ошибки проявляются чаще, чем на средних значениях этого же диапазона. Поэтому для тестов больше подходят граничные значения. Не слишком сложен и не слишком прост Объединив два теста в один, можно сэкономить время на их выполне нии. Но не переусердствуйте — огромный и сложный тест трудно понять, Глава 7: Разработка тестов 1 8 3 трудно выполнить и долго создавать. Поэтому лучше всего придерживать ся золотой середины, разрабатывая простые, но все же не совсем элемен тарные тестовые примеры. Кроме трудоемкости, у сложных тестов есть и более серьезный недоста ток. Скомбинировав несколько неверных входных значений, нельзя сказать наверняка, как программа интерпретирует каждое из них. После первого же недопустимого значения поведение программы может выйти из-под конт роля, например, она может просто отказаться принимать все остальные данные. Такие примеры иногда строятся и намеренно — если необходимо проверить, как программа реагирует на серию недопустимых значений. Однако для начала лучше протестировать их по отдельности, проверив работу блока обработки каждой из ошибок. Некорректное поведение программы проявляется с достаточной очевидностью Как узнать, прошла ли программа тест? Ответ на этот вопрос не так очевиден, как может показаться на первый взгляд. Тут есть над чем поду мать. Даже неверные выходные данные на экране или на бумаге тестиров- щик может случайно пропустить, не говоря уже о том, что результат ошибки может оказаться скрытым. • Разрабатывая тест, подробно опишите ожидаемые выходные данные или реакцию программы. Выполняя его, сверяйтесь со своими запи сями. • Постарайтесь разрабатывать тесты так, чтобы объем выходных дан ных был минимальным. В километровой распечатке или огромном файле едва ли легко будет найти неправильную цифру. Классы эквивалентности и граничные условия Одними из ключевых понятий теории тестирования являются классы эквивалентности и граничные условия. Классический тест граничных ус ловий позволяет с наибольшей вероятностью выявить имеющуюся в программе ошибку. Обдумывая наборы таких тестов, специалист разделяет все возможные тесты на группы, выделяя в каждой из них наиболее эффективные. Классы эквивалентности Если от выполнения двух тестов ожидается один и тот же результат, они считаются эквивалентными. Группа тестов представляет собой класс экви валентности, если выполняются следующие условия. 1 8 4 Часть II: Приемы и технологии тестирования • Все тесты предназначены для выявления одной и той же ошибки. • Если один из тестов выявит ошибку, остальные, скорее всего, тоже это сделают. • Если один из тестов не выявит ошибки, остальные, скорее всего», тоже этого не сделают. Разумеется, кроме этих абстрактных критериев, необходимы еще и практические, позволяющие отнести к одному классу конкретную группу тестов. Вот на чем может основываться этот отбор. Тесты включают значения одних и тех же входных данных. Для их проведения выполняются одни и те же операции программы. В результате всех тестов формируются значения одних и тех же выходных данных. • Либо ни один из тестов не вызывает выполнения блока обработки ошибок программы, либо выполнение этого блока вызывается все ми тестами группы. Поиск классов эквивалентности Поиск классов эквивалентности — процесс субъективный. Два челове ка, анализирующих одну и ту же программу, составят различные перечни классов. Однако постарайтесь все же выявить как можно больше классов эквивалентности: это сэкономит время в дальнейшем и сделает тестирова ние более эффективным, избавляя вас от ненужного повторения эквивален тных тестов. Разбив все предполагаемые тесты на классы, можно затем выделить в каждом из них один или несколько тестов, которые покажутся вам наиболее эффективными — остальные выполнять ни к чему. Вот несколько рекомендаций для поиска классов эквивалентности: • Не забывайте о классах, охватывающих заведомо неверные или недопустимые входные данные. • Организуйте формируемый перечень классов в виде таблицы или плана. • Определите диапазоны числовых значений. • Для полей или параметров, принимающих фиксированные перечни значений, выясните, какие из значений входят в перечень. • Проанализируйте возможные результаты выбора из списков и меню. • Поищите переменные, значения которых должны быть равными. • Поищите классы значений, зависящих от времени. Глава 7: Разработка тестов 1 8 5 • Выявите группы переменных, совместно участвующих в определен ных вычислениях, результат которых ограничивается конкретным набором или диапазоном значений. • Посмотрите, на какие действия программа отвечает эквивалентны ми событиями. • Продумайте варианты операционного окружения. Не забывайте о классах, охватывающих заведомо неверные или недопустимые входные данные Часто недопустимые или неверные входные данные вызывают в про грамме самые разнообразные ошибки. Лишь очень немногие программис ты тщательно продумывают и отлаживают реакцию своих программ на подобные данные. Поэтому, чем больше вы выделите типов неверного ввода, тем больше найдете ошибок. Например, если программа должна принимать числа от 1 до 99, существует как минимум четыре класса экви валентных тестов. • Допустим ввод чисел от 1 до 99. • Любое число меньше 1 слишком мало. Данный диапазон включает О и все отрицательные числа. • Любое число больше 99 слишком велико. • Если введена нечисловая информация, она не принимается. (Дей ствительно ли это верно для всего, что не является числом?) Организуйте формируемый перечень классов в виде таблицы или плана Обычно классов эквивалентности оказывается очень много, так что не обойтись без удобного и продуманного способа организации собранной информации. Мы используем два подхода. Обычно вся информация сво дится в большую таблицу, пример которой приведен на рис. 7.1. Иногда ее можно представить и в форме плана, как на рис. 7.2. Обратите внимание, что в любом случае в перечень включены тесты не только допустимых, но и недопустимых или нестандартных входных данных. Оба способа организации информации, и таблица и план, достаточно удобны. У каждого из них есть преимущества и недостатки. Табличный формат информации более понятен, его легче читать, и одним взглядом можно охватить больше информации. В нем более очевид но разделение на допустимые и недопустимые варианты. На наш взгляд, 1 8 6 Часть II: Приемы и технологии тестирования когда информация представлена в таком виде, ее легче анализировать, чтобы выяснить, все ли недопустимые варианты входных данных охваче ны перечисленными классами эквивалентности. К сожалению, таблицы часто бывают очень громоздки. Как правило, в них больше столбцов, чем показано на рис. 7.1, — в этих столбцах отража ется взаимодействие между различными элементами данных, события раз биваются на подсобытия, или классы эквивалентности разделяются на подклассы. Например, событие "Ввод имени" может быть разбито на со бытия "Ввод первой буквы имени" и "Ввод оставшейся части имени". Можно нарисовать огромную черновую таблицу, а затем превратить ее в таблицу с тремя столбцами, используя для развития одной и той же темы новые строки. Но при таком способе представления данных теряется ос новное преимущество таблицы — ее наглядность. Сразу исчезают все логи ческие связи, так прекрасно представленные в широкой таблице. Глава 7: Разработка тестов 1 8 7 l88 Часть II: Приемы и технологии тестирования Можно рисовать таблицу на большом листе ватмана и вешать на стене, но в бумажном варианте ее трудно дополнять и делать фотокопии. Гораз до удобнее пользоваться электронными таблицами. Если нужно распечатать результат, можно напечатать таблицу полосами, а потом их склеить. Планы можно также составлять с помощью компьютера. Соответству ющее программное обеспечение позволяет их с легкостью дополнять, ре организовывать, форматировать и печатать. Планы выглядят компактнее, и в них легче разбивать информацию на составляющие. Однако и повторения при использовании планов случают ся чаще. Мы не считаем ни один из этих двух подходов более эффективным. Они оба достаточно хороши. Приведенный на рис. 7.2 план иллюстрирует одну практическую про блему. Посмотрите на раздел 1.2.5.2, в котором идет речь об арифметичес ких операторах. Концептуально они представляют собой самостоятельный класс эквивалентности, и программист может именно так их и рассматри вать, проверяя работу программы с каждым из операторов. Теперь взгля ните на разделы 1.2.5.3.1 и 1.2.5.3.2. В них тоже включаются все арифметические операторы. Как же поступать с пересекающимися классами? Поскольку совершенно неизвестно, как в каждом конкретном случае поступает программист, об щего правила, основывающегося на классификации данных программис том, здесь быть не может. Простейший способ обычно самый лучший. Примечание в схеме, ука зывающее на подобные накладки, поможет тестировщику избежать повто рений при тестировании. Не стоит долго ломать голову над тем, как определить классы, которые бы не пересекались. Определите диапазоны числовых значений Каждый раз, когда обнаруживается новый диапазон значений, вместе с ним появляется и несколько классов эквивалентности. Обычно среди них имеется три недопустимых класса: все числа, которые меньше нижнего граничного значения диапазона, все числа, большие его верхнего гранич ного значения, и нечисловые данные. Иногда один из этих классов отсутствует. Например, допускаются числа любой величины. Убедитесь, что это и в самом деле так. Попробуйте вве сти очень большое число и посмотрите, что получится. Посмотрите также, нет ли у значений исследуемого параметра подди апазонов, как, например, у налоговых ставок. Каждый поддиапазон будет отдельным классом эквивалентности. Недопустимые классы будут распола гаться ниже самого нижнего диапазона и выше верхнего из них. Глава 7: Разработка тестов 1 8 9 Для полей или параметров, принимающих фиксированные перечни значений, выясните, какие из значений в них входят Если для параметра допускается только определенный перечень значе ний, один из классов эквивалентности может включать все значения из этого перечня, а другой — все остальные значения. В дальнейшем эти два класса можно будет разделить на ряд меньших классов. Например, если в некоторое поле вводится название страны, класс допустимых значений включает названия всех стран планеты. В класс недопустимых значений будет входить любое сочетание символов, которое является названием страны. Однако как быть с аббревиатурами, ошибками при написании, особен ностями национального произношения названий стран или старыми назва ниями, которые сейчас отсутствуют. Следует ли проверять подобные значения, выделив их в отдельные классы? Вполне вероятно, что, посколь ку спецификацией все эти варианты не предусмотрены, при попытке их ввести можно столкнуться с ошибкой. При вводе названий программа может сразу же проверять вводимые символы. Они должны быть буквами верхнего или нижнего регистра. Все, что не является буквами, относится к классу недопустимых значений. Его, в свою очередь, можно разбить на подклассы. Следует учесть и символы разных языков, в том числе и акцентированные символы, которых тоже достаточно много. Проанализируйте возможные результаты выбора из списков и меню Любой элемент предложенного программой списка опций может, по существу, представлять собой отдельный класс эквивалентности. Каждый элемент меню или списка опций обрабатывается программой особым об разом, поэтому все они подлежат проверке. К классу недопустимых значе ний относятся ответы пользователя, которых нет в списке (если программа позволяет не только выбирать, но и вводить значения опций). Например, если программа задает вопрос "Вы уверены? (Д/Н)", один класс эквивалентности должен содержать ответ Д (и, межу прочим, также и д), а второй — ответ Н (и н). Все остальные ответы являются недопус тимыми (хотя вполне возможно, что программа интерпретирует все, что не является положительным ответом, как отрицательный, т.е. как эквивалент ответа Н). А вот другой пример. Американские налогоплательщики разделяются на неженатых, женатых с объединенным доходом, женатых с разделенным доходом, домохозяек и вдов с зависимыми детьми. Некоторые из них от- 1 9 0 Часть II: Приемы и технологии тестирования казываются описывать свое семейное положение, что также законно. Не которые люди заявляют, что не подходят ни под одну из перечисленных категорий, и пишут в налоговой декларации примечание, поясняющее причину. Таким образом формально их семейное положение можно отне сти к классу недопустимых значений. Поищите переменные, значения которых должны быть равными В свое время Форд утверждал, что готов выпускать автомобили любо го цвета, пока они будут оставаться черными. Все не черные цвета в этом примере можно отнести к классу недопустимых значений. Иногда ограни чение, налагаемое программой на значения поля, оказывается совершенно неожиданным. Значения, которые обычно вполне приемлемы, но в данном месте программой не принимаются, относятся к отдельному классу экви валентности. Поищите классы значений, зависящих от времени Предположим, что вы нажимаете клавишу пробела непосредственно перед, во время и сразу после того, как система загрузит программу. Как ни странно, но подобные тесты разрушали некоторые системы. Какие классы эквивалентности можно выделить в подобной ситуации? К перво му из них относятся все события, происходящие задолго до выполнения задания, ко второму — события, происходящие в короткий отрезок времени непосредственно перед выполнением задания, к третьему — период его выполнения и т.д. Подобным образом можно направить задание на принтер, когда тот свободен, занят, сразу после завершения им печати документа. Можно попробовать выполнить то же самое в многопользовательской системе: что, если ваш приоритет выше, чем у пользователя, печатающего в данный момент? Выявите группы переменных, совместно участвующих в определенных вычислениях, результат которых ограничивается конкретным набором или диапазоном значений Введите величины трех углов треугольника. К классу допустимых отно сятся значения, в сумме дающие 180 градусов. Недопустимые значения можно разделить на два класса эквивалентности: с суммарным значением менее 180 и более 180 градусов. Глава 7: Разработка тестов 1 9 1 Посмотрите, на какие действия программа отвечает эквивалентными событиями До сих пор рассматривались только входные события, поскольку это первое, что приходит в голову, да и анализировать их гораздо легче. Тре тье событие на рисунках 7.1 и 7.2 является выходным. Программа чертит линию длиной до четырех сантиметров, причем линия предполагается прямой, но может оказаться и другой формы, например, окружностью. Трудность состоит в том, чтобы определить, какие входные данные управляют длиной и формой линии. Иногда различные классы входных данных на выходе дают один и тот же эффект. Но если точный путь обра ботки каждого класса входных данных вам неизвестен, лучше все равно интерпретировать их как разные классы и тестировать по отдельности. Особенно это важно в тех случаях, когда в ответ на определенные входные данные при формировании выходной информации генерируется ошибка и управление передается блоку ее обработки. Еще одним примером может послужить программа, которая после се рии вычислений должна печатать число между 1 и 45. В данном случае следует проанализировать, какие входные данные заставят ее напечатать число, которое больше 45 или меньше 1. Для проверки необходимо прове сти ряд тестов. Продумайте варианты операционного окружения Предположим, что программа предназначена для работы на компьютере с объемом памяти от 64 до 256 Кб. Эти значения определяют один класс эквивалентности. К другому классу будут относиться объемы памяти, ко торые меньше 64 Кб. Еще к одному — объемы памяти, превышающие 256 Кб. Некоторые известные программы отказывались работать на компьюте рах, имеющих больше ожидаемого объема памяти. Бывает, что программа хорошо работает только с определенными типа ми мониторов, принтеров, модемов, дисковых устройств или любого дру гого подключенного к системе оборудования. Работа программы может зависеть даже от тактовой частоты компьютера. Поэтому, анализируя про грамму, особенно выполняющую низкоуровневые операции с оборудовани ем или ориентирующуюся на его определенные возможности, очень важно определить классы эквивалентных конфигураций системы. Границы классов эквивалентности Для каждого класса эквивалентности достаточно провести один-два теста. И лучшими из них будут те, которые проверяют значения, лежащие на границах класса. Они могут быть наибольшими, наименьшими, быстрей- 1 9 2 Часть II: Приемы и технологии тестирования шими, кратчайшими, самыми громкими, самыми красивыми — но в любом случае это должны быть предельные значения параметров класса. Непра вильные операторы сравнения (например, > вместо >=) вызывают ошиб ки только на граничных значениях аргументов. В то же время программа, которая сбоит на промежуточных значениях диапазона, почти наверняка будет сбоить и на граничных. Необходимо протестировать каждую границу класса эквивалентности, причем с обеих сторон. Программа, которая пройдет эти тесты, скорее всего, пройдет и все остальные, относящиеся к данному классу. Вот ряд примеров. • Если допустимы значения от 1 до 99, для тестирования допустимых данных можно выбрать 1 и 99, а для тестирования недопустимых — О и 100. • Если программа выписывает чеки на суммы от $1 до $99, то стоит попробовать выписать чек на отрицательную сумму, на $0, на $100. • Если программа ожидает заглавную английскую букву, введите А и Z. Проверьте также символ @, поскольку его код предшествует коду символа А, и символ ], код которого следует за кодом символа Z. Кроме того, проверьте символы а и г. • Если программа рисует линии длиной от одной точки до 4 сантимет ров, нарисуйте одну точку и линию длиной ровно 4 сантиметра. Пусть программа также попробует нарисовать линию нулевой длины. • Если сумма входных значений должна равняться 180, попробуйте ввести значения, дающие в сумме 179, 180 и 181. • Если программа получает определенное количество входных данных, попробуйте ввести в точности необходимое количество, на единицу "меньшее и на единицу большее. • Если программа принимает ответы В, С и D, попробуйте ввести А и Е. • Попробуйте отправить на печать файл непосредственно перед и сразу после того, как принтер напечатает еще чье-либо задание. • После чтения и записи файла на диск проверьте его первый и пос ледний символы. Анализируя границы диапазонов значений, очень важно учесть все возможные выходные данные. Проанализируйте каждый элемент распечат ки или изображения на экране. Каковы допустимые перечни или макси мальные и минимальные значения каждого печатаемого параметра? Можно ли заставить программу сформировать данные, выходящие за эти границы, и как это сделать? Глава 7: Разработка тестов 1 9 3 Следует иметь в виду, что между граничными значениями входных и выходных данных нет непосредственного соответствия. Показательным примером могут служить простейшие тригонометрические функции. Многие тестировщики включают в наборы тестовых данных и средние значения диапазонов. Это хорошая практика, особенно когда достаточно времени. Тестирование переходов между состояниями В каждой интерактивной программе осуществляются переходы из одно го очевидного состояния в другое. Если изменяется набор предлагаемых пользователю вариантов или меняется изображение на экране, это означает изменение состояния программы. (Более подробно о переходах между со стояниями программ можно прочитать у Бейзера (Beizer, 1983).) Простейшим примером может служить меню. После запуска програм мы в нем имеется один перечень команд. После выбора одной из них состояние программы меняется и в меню появляются команды, доступные в этом новом состоянии. Кроме того, на экране сменяется информация: отображаются формы ввода данных, их просмотра и т.д. Необходимо протестировать каждую предлагаемую программой оп цию, каждую команду меню. Команда 15 может быть доступна в режи ме, открываемом по команде 14 и по команде 27. В этом случае команду 15 придется протестировать дважды — в обоих режимах. Однако команд меню и всевозможных режимов программы и путей перехода в эти ре жимы может быть так много, что протестировать их все просто нереаль но: клавиатура сотрется прежде, чем вы проведете все возможные тесты. Поэтому, отбирая тесты для проверки путей выполнения программы, лучше всего руководствоваться следующими критериями. • Протестируйте все наиболее вероятные последовательности действий пользователей. • Если можно предположить, что действия пользователя в одном ре жиме могут воздействовать на представление данных или набор предоставляемых программой возможностей в другом режиме, про тестируйте эту зависимость. • Кроме проведения самых необходимых тестов — из тех, что описа ны выше, — стоит поработать с программой в произвольном режи ме, случайным образом выбирая путь ее выполнения. Переходы между состояниями могут быть гораздо более сложными, чем просто выбор команд меню. Содержимое и структура очередной формы 1 9 4 Часть II: Приемы и технологии тестирования ввода данных может зависеть от информации, введенной в предыдущей форме. Значения одних полей могут определять допустимые значения дру гих. Или же ввод определенной информации может инициировать серию дополнительных запросов. Например, при вводе числа от 1 до 99 программа выводит одну форму, а при вводе любого другого числа — другую. В этом случае вместе с классами эквивалентности и их граничными значениями придется проанализировать и возможные пути выполнения программы, чтобы составить действительно полноценный набор тестов. Некоторые тестировщики находят полезным составление схем меню. В подобной схеме отражаются все состояния программы и команды, вызыва ющие переходы между этими состояниями. В нее включаются команды, активизируемые через меню, через графические средства (например, раз личные кнопки), и команды, выполняемые по нажатию определенных клавиш. Например, в схеме может быть показан путь от меню Файл к команде Открыть, затем к диалоговому окну Открытие файла и назад к основному состоянию программы. Особенно удобны подобные схемы в случае, если структура программы напоминает спагетти: определенное диалоговое окно можно открыть несколькими способами и выйти из него в несколько различных режимов. В этом случае можно нарисовать на схе ме все направления переходов и по ним протестировать программу. Это более аккуратный способ, чем работать с программой без всякого плана, рискуя пропустить важные взаимосвязи ее состояний. Условия гонок и другие временные зависимости Может ли программа выполняться слишком быстро или слишком мед ленно? Чтобы это проверить, можно воспользоваться кнопкой переключе ния тактовой частоты компьютера (если она есть), попробовать поработать на более скоростном или, наоборот, менее скоростном компьютере либо увеличить нагрузку на собственный компьютер, запустив параллельно на выполнение еще несколько программ. Попробуйте вмешаться в работу программы, когда она выполняет пере ход между двумя состояниями. Понажимайте клавиши, особенно команд ные, или направьте ей программные сообщения, если это возможно. Попробуйте понажимать клавиши или выполнить в программе какие-ни будь действия, когда она выполняет операции обработки данных или вво да/вывода, предложите программе ввести или вывести параллельно еще какую-нибудь информацию. Например, во время печати одного файла по просите ее распечатать еще один. Если в программе определены ситуации тайм-аута, когда она ждет определенного события в течение заданного времени, а затем переходит в |