Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Роббинс Д. - Отладка приложений для Microsoft .NET и Microsoft Windows - 2004

.pdf
Скачиваний:
321
Добавлен:
13.08.2013
Размер:
3.3 Mб
Скачать

ГЛАВА 2 Приступаем к отладке

51

 

 

вызывают компиляцию файла .I, поэтому при компоновке программы вы столкнетесь с ошибками. Определив проблему, отключайте их. Знаю на собственном опыте: регистрация проекта в системе управления версиями с заданными ключами /EP и /P не понравится ни вашим товарищам по группе, ни руководителю.

/X

(игнорировать стандартный путь включения файлов)

Создание правильной компоновки может оказаться проблематичным, если на компьютере установлены несколько компиляторов и пакетов для разра$ ботки ПО (SDK). Если не задан ключ /X, компилятор, вызываемый MAK$ файлом, вызовет переменную среды INCLUDE. Ключ /X позволяет контроли$ ровать включение заголовочных файлов: он заставляет компилятор игно$ рировать переменную INCLUDE и искать заголовочные файлы только в мес$ тах, указанных явно посредством ключа /I. Задать ключ /X можно, открыв окно Property Pages, папку C/C++, страницу Preprocessor и выбрав соответ$ ствующее значение в поле Ignore Standard Include Path (игнорировать стан$ дартный путь включения файлов).

/Zp

(выравнивание членов структур)

Этот флаг использовать не следует. Выравнивание членов структур в памя$ ти надо задавать не в командной строке, а в директиве #pragma pack в специ$ фических заголовочных файлах. Невыполнение этого условия порой при$ водит к очень трудноуловимым ошибкам. Начиная проект, разработчики задавали ключ /Zp. Когда они переходили к другой компоновке или если работу над кодом продолжала другая группа, про ключ /Zp забывали, и струк$ туры начинали немного отличаться, так как по умолчанию применялся иной метод выравнивания. На поиск причины тех ошибок пришлось потратить кучу времени. Для установки этого ключа нужно открыть окно Property Pages, папку C/C++, выбрать страницу Code Generation (генерирование кода) и задать нужное значение свойства Struct Member Alignment (выравнивание членов структур).

Используя директиву #pragma pack, не забывайте про ее новый вариант #pragma pack (show), выводящий при компиляции значение выравнивания в окно Build. Это поможет вам следить за текущим выравниванием в различ$ ных разделах кода.

/Wp64

(определять проблемы совместимости с 64-разрядными

 

платформами)

Этот ключ позволяет сэкономить много времени при работе над совмес$ тимостью кода с 64$разрядными системами. Установить его можно, открыв окно Property Pages, папку C/C++, выбрав страницу General и задав в поле Detect 64$bit Portability Issues (определять проблемы совместимости с 64$ разрядными платформами) значение Yes (/Wp64). Лучше всего /Wp64 при$ менять с самого начала проекта. Если вы зададите этот ключ, уже проделав значительную работу над программой, то вас поразит количество обнару$ женных проблем, так как он предъявляет очень высокие требования. Кро$

см. след. стр.

52 ЧАСТЬ I Сущность отладки

ме того, некоторые поставляемые Microsoft макрокоманды, которые, как предполагалось, помогут решить вопросы совместимости с платформами Win64, например SetWindowLongPtr, при компиляции с ключом /Wp64 приво$ дят к выводу сообщений об ошибке.

/RTC

(проверка ошибок в период выполнения)

Самые полезные ключи, известные сообществу программистов на C++! Всего их три: /RTCc обеспечивает проверку потери данных при их преобразова$ нии в меньший тип, /RTCu помогает предотвращать использование неини$ циализированных переменных, /RTCs проверяет кадры стека путем иници$ ализации всех локальных переменных известным значением (0xCC), предот$ вращает применение недопустимых индексов локальных переменных и проверяет правильность указателей стека для предотвращения искажения данных. Для установки этих ключей откройте окно Property Pages, папку C/ C++, страницу Code Generation и выберите соответствующие значения в полях Smaller Type Check (проверка при преобразовании к меньшему типу) и Basic Runtime Checks (базовые виды проверки периода выполнения). Эти ключи настолько важны, что в главе 17 мы обсудим их особо.

/GS

(проверка безопасности буферов)

Один из наиболее распространенных приемов в арсенале создателей ви$ русов — переполнение буфера, при котором адрес возврата перезаписыва$ ется так, чтобы управление получал код злоумышленника. К счастью, ключ /GS позволяет включить в программу специальные фрагменты, гарантиру$ ющие, что адрес возврата не был перезаписан. Это значительно затрудняет создание вирусов такого типа. Ключ /GS задан по умолчанию для заключи$ тельных компоновок, и я также советую использовать его в отладочных компоновках. Если когда$нибудь этот ключ сообщит, что кто$то перезапи$ сал только адрес возврата, вы увидите, как много недель ужасно сложной отладки это вам сэкономит. Установите ключ /GS, открыв окно Property Pages, папку C/C++, страницу Code Generation и задав в поле Buffer Security Check (проверка безопасности буферов) значение Yes (/GS). В главе 17 я объяс$ ню, как изменять принятые по умолчанию сообщения об ошибках, обна$ руженных ключом /GS.

/O1

(минимизировать размер кода)

В проектах C++, создаваемых мастерами, для заключительных компоновок по умолчанию применяется ключ /O2 (максимизировать скорость). Однако Microsoft создает все свои коммерческие приложения с ключом /O1, и вам также следует делать это. Задать этот ключ можно, открыв окно Property Pages, папку C/C++, страницу Optimization и выбрав соответствующие значение свойства Optimization. Программисты Microsoft обнаружили, что после на$ хождения наилучшего алгоритма и написания компактного кода скорость выполнения приложения можно значительно повысить, уменьшив число ошибок страниц памяти. Как я слышал, они говорят: «Ошибки страниц могут испортить вам весь день!»

ГЛАВА 2 Приступаем к отладке

53

 

 

Страница представляет собой наименьший блок кода или данных (4 кб для компьютеров с архитектурой x86), с которым диспетчер памяти может работать как с единым целым. Ошибка страницы происходит при обраще$ нии к недействительной странице памяти. Это может быть обусловлено самыми разными причинами: например, попыткой получения доступа к странице из списка резервных или измененных страниц или к странице, которая больше не находится в памяти. Для исправления ошибки страни$ цы ОС должна прекратить выполнение программы и загрузить в регистры процессора новый адрес страницы. Если ошибка страницы «мягкая» (т. е. страница уже находится в памяти), накладные расходы не очень велики, тем не менее они все равно лишние. Однако если ошибка «жесткая», ОС вынуж$ дена загрузить в память нужную страницу с диска. Разумеется, это требует выполнения сотен тысяч команд, замедляя работу приложения. Минимиза$ ция объема двоичного файла позволяет уменьшить общее число использу$ емых приложением страниц, а значит, и снизить вероятность ошибок стра$ ницы. Пусть загрузчик и диспетчер управления кэш$памятью ОС очень хо$ роши, но зачем допускать больше ошибок страниц, если есть возможность уменьшить их число?

Кроме задания ключа /O1, рекомендую подумать об утилите Smooth Wor$ king Set (SWS) из главы 19, которая помогает вынести наиболее часто вы$ зываемые функции в начало двоичного файла, минимизировав таким об$ разом рабочий набор, т. е. число страниц, находящихся в оперативной па$ мяти. Если часто используемые функции расположены в начале файла, ОС сможет выгрузить ненужные страницы на диск. Это позволит ускорить выполнение приложения.

/GL

(оптимизация всей программы)

Программисты Microsoft много сделали для улучшения генераторов кода, благодаря чему компактность и скорость выполнения программ, создавае$ мых в среде Visual C++ .NET, заметно улучшились. Одно из крупных изме$ нений состоит в том, что вместо оптимизации отдельных файлов (извест$ ных также как компилянды) при компиляции теперь можно выполнять кросс$ файловую оптимизацию программы при ее компоновке. Я уверен, что все программисты, впервые компилирующие проект C++ в среде Visual C++ .NET, замечают серьезное уменьшение объема программы. Удивительно, но для заключительных компоновок Visual C++ этот ключ по умолчанию не исполь$ зуется. Установите его: откройте окно Property Pages, папку Configuration Properties, страницу General и задайте в поле Whole Program Optimizations (оптимизация всей программы) значение Yes. Это одновременно установит и соответствующий ключ компоновщика, /LTCG.

/showIncludes

(выводить список включаемых файлов)

О назначении этого ключа говорит само название. При компиляции файла он составляет иерархический список всех включаемых файлов, позволяю$ щий узнать, что, куда и откуда включается. Задайте этот ключ, открыв окно

см. след. стр.

54 ЧАСТЬ I Сущность отладки

Property Pages, папку C/C++, страницу Advanced и указав в поле Show Includes (показывать включаемые файлы) значение Yes (/showIncludes).

Ключи для компоновщика LINK.EXE

Задать эти ключи вручную можно, открыв окно Property Pages, папку Linker, страницу Command Line и введя их в текстовом поле Additional Options, однако гораздо лучше указывать их в соответствующих им местах. Как я уже писал в разделе, посвященном ключам компилятора, программисты не при$ выкли искать ключи командной строки в текстовом поле Additional Options, так что это может привести к проблемам.

/MAP

(генерировать MAP-файл)

/MAPINFO:LINES

(включать в MAP-файл номера строк)

/MAPINFO:EXPORTS

(включать в MAP-файл информацию об экспортируемых

 

функциях)

Эти ключи обеспечивают создание MAP$файла для компонуемого образа программы (о MAP$файлах см. главу 12). Я советую всегда создавать MAP$ файл, так как это единственный способ получения информации о симво$ лах в текстовом виде. Используйте все три ключа, чтобы MAP$файл содер$ жал наиболее полную информацию. Задать их можно, открыв окно Property Pages, папку Linker и выбрав нужные значения на странице Debugging.

/NODEFAULTLIB

(игнорировать библиотеки)

Многие системные заголовочные файлы включают директивы #pragma comment ( lib#, XXX ), определяющие, с какой библиотекой компоновать файл, где XXX — название библиотеки. Ключ /NODEFAULTLIB указывает компоновщику игнорировать эти директивы. Данный ключ позволяет программисту самому выбирать компонуемые библиотеки и порядок компоновки. Вам придется указывать все нужные библиотеки в командной строке компоновщика, но вы хотя бы будете точно знать, какие библиотеки вы используете и в каком порядке. Управление порядком компоновки может оказаться очень важным, когда один символ встречается в нескольких библиотеках, что может при$ водить к трудноуловимым ошибкам. Задать этот ключ можно, открыв окно Property Pages, папку Linker, страницу Input (ввод) и указав в поле Ignore All Default Libraries (игнорировать все библиотеки, используемые по умолча$ нию) значение Yes.

/OPT:NOWIN98

Если от вашей программы не требуется поддержка ОС Windows 9x/Me, этот ключ позволит немного уменьшить размер исполняемых файлов, сняв ог$ раничение, требующее, чтобы их разделы выравнивались по границе 4 кб. Для установки этого ключа нужно открыть окно Property Pages, папку Linker, страницу Optimization и задать нужное значение в поле Optimize For Win$ dows98 (оптимизировать программу для ОС Windows98).

 

ГЛАВА 2 Приступаем к отладке

55

 

 

 

 

 

 

 

 

 

/ORDER

(располагать функции в определенном порядке)

 

Если вы собираетесь применять утилиту Smooth Working Set (см. главу 19), ключ /ORDER позволит указать файл, описывающий порядок расположения функций. Он отключает компоновку с приращением, поэтому задавайте его только для завершающих компоновок. Этот ключ задается так: откройте в окне Property Pages папку Linker, страницу Optimization и введите значение в поле Function Order (порядок функций).

/VERBOSE

(выводить сообщения о прогрессе компоновки)

/VERBOSE:LIB

(выводить только сообщения, касающиеся поиска

 

библиотек)

В случае проблем с компоновкой эти сообщения смогут показать вам, ка$ кие символы ищет компоновщик и где он их находит. Информация может оказаться очень объемной, но, возможно, она поможет вам найти причину проблемы. Однажды эти два ключа помогли мне при отладке очень стран$ ной ошибки, когда на уровне ассемблера вызываемая функция выглядела совсем не так, как я предполагал. Оказалось, что в двух разных библиоте$ ках имелись две различных функции с одинаковыми сигнатурами, и ком$ поновщик использовал неправильный вариант. Задать эти ключи можно, открыв окно Property Pages, папку Linker, страницу General, в поле Show Progress (показывать информацию о прогрессе компоновки).

/LTCG

(генерация кода во время компоновки)

Используется вместе с ключом компилятора /GL для выполнения перекрес$ тной оптимизации компиляндов. Он устанавливается автоматически при задании ключа /GL.

/RELEASE

(задание контрольной суммы)

Если ключ /DEBUG указывает компоновщику генерировать отладочный код, то неверно названный ключ /RELEASE не делает, как можно было бы пред$ положить, противоположное и не приказывает компоновщику создать оп$ тимизированную заключительную компоновку. Вообще$то этот ключ сле$ довало бы назвать /CHECKSUM. Он всего лишь вносит значения контрольной суммы в заголовок файла Portable Executable (PE). Это необходимо для заг$ рузки драйверов устройств, но не нужно приложениям, работающим в поль$ зовательском режиме. Однако установка этого ключа для завершающих ком$ поновок будет совсем не лишней, так как отладчик WinDBG (см. главу 8) всегда выводит соответствующее сообщение, если двоичный файл не содер$ жит значения контрольной суммы. В отладочных компоновках ключ /RELEASE использовать не следует, так как он требует отключения компоновки с при$ ращением. Чтобы установить ключ /RELEASE для завершающих компоновок, откройте окно Property Pages, папку Linker, страницу Advanced и выберите в поле Set Checksum (использовать контрольную сумму) значение Yes (/RELEASE).

см. след. стр.

56

ЧАСТЬ I

Сущность отладки

 

 

 

 

 

 

 

 

 

 

 

 

/PDBSTRIPPED

(не включать частные символы в PDB-файл)

 

 

 

Одной из сложнейших отладочных проблем является получение чистого

 

 

 

стека вызовов. Причина, по которой вы не можете получить хорошие сте$

 

 

 

ки вызовов, в том, что код «плавающих стеков» не включает специальных

 

 

 

данных о кадре стека с отсутствующим указателем (FPO, Frame pointer omis$

 

 

 

sion), которые помогли бы расшифровать имеющийся стек. Так как данные

 

 

 

FPO для вашего приложения содержатся в PDB$файлах, вы можете просто

 

 

 

предоставить эти файлы клиенту. Конечно, это вполне обоснованно заста$

 

 

 

вит вас и вашего менеджера нервничать, но не забывайте, что до появле$

 

 

 

ния Visual C++ .NET у вас было гораздо больше проблем с получением чис$

 

 

 

тых стеков вызовов.

 

 

 

Если вы когда$нибудь устанавливали символы ОС от Microsoft (см. раз$

 

 

 

дел «Установите символы ОС и создайте хранилище символов»), вы, веро$

 

 

 

ятно, заметили, что символы Microsoft предоставляли вам полную инфор$

 

 

 

мацию о стеках вызовов, не выдавая никаких секретов. Для этого програм$

 

 

 

мисты Microsoft делают следующее: они включают в PDB$файлы только

 

 

 

открытые функции и крайне важные данные FPO, но не закрытую инфор$

 

 

 

мацию вроде переменных и данных об исходных кодах и номерах строк.

 

 

 

Ключ /PDBSTRIPPED позволяет вам безопасно создавать аналогичный тип

 

 

 

символов для своего приложения, не выдавая никаких секретов. Есть новость

 

 

 

и получше: сокращенный PDB$файл генерируется одновременно с его пол$

 

 

 

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

 

 

 

завершающих компоновок. Откройте диалоговое окно проекта Property Pages,

 

 

 

папку Linker, страницу Debugging и задайте в поле Strip Private Symbols (не

 

 

 

включать закрытые символы) расположение и название файла символов. Я

 

 

 

всегда использую строку $(OutDir)/ $(ProjectName)_STRIPPED.PDB, чтобы было

 

 

 

ясно, какой PDB$файл является сокращенной версией, а какой — полной.

 

 

 

Если вы отсылаете сокращенные PDB$файлы заказчику, удалите из назва$

 

 

 

ний часть «_STRIPPED», чтобы их могли загрузить такие программы, как

 

 

 

Dr. Watson.

 

 

 

 

 

 

 

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

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

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

ГЛАВА 2 Приступаем к отладке

57

 

 

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

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

Ответ на вопрос, что^ протоколировать, зависит главным образом от проекта, однако в любом случае нужно регистрировать хотя бы ошибочные и аномальные ситуации. Кроме того, следует попытаться учесть логический смысл операции программы. Так, если ваша программа работает с файлами, не стоит записывать в журнал такие подробности, как «Переходим в файле к смещению 23»; вместо это$ го нужно протоколировать открытие и закрытие файла. Тогда, увидев, что после$ дняя запись в журнале гласит «Подготавливаем открытие D:\Foo\BAR.DAT», вы уз$ наете, что ваш BAR.DAT скорее всего поврежден.

Глубина протоколирования зависит также от вызываемого им снижения про$ изводительности. Я обычно протоколирую все, что мне может понадобиться, и наблюдаю за производительностью заключительных компоновок, когда протоко$ лирование не ведется. Современные средства слежения за производительностью позволяют легко узнать, получает ли управление ваш код протоколирования. Если да, вы можете немного снизить объем регистрируемой информации, пока не до$ стигнете приемлемого баланса с производительностью приложения. Определить, что^ именно протоколировать, сложно. В главе 3 я расскажу, что нужно протоко$ лировать в управляемых приложениях, а в главе 18 покажу, как выполнять высо$ коскоростную трассировку неуправляемых приложений с минимальными усили$ ями. Другим полезным средством является очень быстрая, но неправильно назван$ ная система Event Tracing, встроенная в Windows 2000 и более поздние версии (см. о ней по адресу: http://msdn.microsoft.com/library/default.asp?url=/library/en$us/ perfmon/base/ event_tracing.asp).

Частые сборки программы

и дымовые тесты обязательны

Два из самых важных элементов инфраструктуры — система сборки программы и комплект дымовых тестов. Система сборки выполняет компиляцию и компоновку программы, а комплект дымовых тестов включает тесты, которые запускают про$ грамму и подтверждают, что она работает. Джим Маккарти (Jim McCarthy) в кни$ ге «Dynamics of Software Development» (Microsoft Press, 1995) называет ежеднев$ ное проведение сборки программы и дымовых тестов сердцебиением проекта. Если эти процессы неэффективны, проект мертв.

58 ЧАСТЬ I Сущность отладки

Частые сборки

Проект надо собирать каждый день. Порой мне говорят, что некоторые проекты бывают столь огромны, что их невозможно собирать каждый день. Означает ли это, что они включают более 40 миллионов строк кода, лежащих в основе Windows XP или Windows Server 2003? Учитывая, что эти ОС — самые масштабные коммер$ ческие программные проекты в истории и все же собираются каждый день, я так не думаю. Итак, неежедневная сборка программы оправданий не имеет. Вы не только должны собирать проект каждый день, но и автоматизировать этот процесс.

При сборке следует одновременно собирать и заключительную, и отладочную компоновки. Как я покажу ниже, отладочные компоновки очень важны. Неудач$ ная сборка программы — большой грех. Если разработчики зарегистрировали код, который не компилируется, виновного нужно наказать. Публичная порка, веро$ ятно, была бы несколько жесткой формой наказания (хотя и не слишком), но есть

идругой метод: заставьте провинившегося публично раскаяться в преступлении

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

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

Чтобы избежать проблем со сборкой программы, каждый член группы должен иметь одинаковые версии всех инструментов и компонентов сборки. Как я уже упоминал, в некоторых группах это гарантируется путем хранения системы сборки программы в системе управления версиями. Если члены группы работают с раз$ ными версиями инструментов, включая разные версии пакетов обновлений (service pack), они создают идеальную почву для ошибок при сборке программы. Если убедительных причин использования кем$нибудь другой версии компилятора нет, никакой разработчик не должен обновлять свои инструменты по собственной воле. Кроме того, все члены группы должны использовать для сборки своих частей программы одни и те же сценарии и компьютеры. Так образуется надежная связь между тем, что создается разработчиками, и тем, что тестируется тестировщиками.

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

ГЛАВА 2 Приступаем к отладке

59

 

 

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

Стандартный вопрос отладки

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

Как только вы завершили разработку функциональности приложения, что также известно как стадия бета$1, вам определенно не следует модернизи$ ровать никакие инструменты. Схема оптимизации нового компилятора, какой бы хорошей она ни казалась, не оправдывает изменения кода про$ граммы. Ко времени достижения стадии бета$1 значительный объем тести$ рования уже выполнен, и, если вы измените инструменты, начать его при$ дется с нуля.

Дымовые тесты

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

Дымовой тест представляет собой просто контрольную таблицу функций, ко$ торые может выполнять программа. Начните с малого: установите приложение, запустите его и закройте. По мере цикла разработки дымовые тесты также долж$ ны развиваться, чтобы можно было исследовать новые функции программы. Ды$ мовой тест должен включать по крайней мере по одному тесту для каждой функ$ ции и каждого крупного компонента программы. Это значит, что, работая в отде$ ле готовой продукции, вы должны тестировать каждую функцию, упомянутую в рекламных проспектах. Если вы сотрудник ИТ$отдела, тестируйте основные фун$ кции, которые вы обещали реализовать менеджеру по информатизации и своим клиентам. Помните: дымовой тест вовсе не должен проверять абсолютно все пути выполнения вашей программы, его надо использовать, чтобы узнать, выполняет ли программа основные функции. Как только она прошла дымовой тест, сотруд$ ники отдела технического контроля могут начинать свой тяжкий труд, пытаясь нарушить работу программы новыми изощренными способами.

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

60 ЧАСТЬ I Сущность отладки

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

В идеале при проведении дымового теста выполнение программы должно быть автоматизировано, чтобы она могла работать без взаимодействия с пользовате$ лем. Инструмент, применяемый для автоматизации ввода информации и выпол$ нения действий с приложением, называется средством регрессивного тестирова$ ния. Увы, не всегда можно автоматизировать тестирование каждой функции, осо$ бенно при изменении UI. На рынке много хороших средств регрессивного тес$ тирования, поэтому, если вы работаете над крупным сложным приложением и не можете позволить себе, чтобы кто$либо из вашей группы отвечал исключительно за проведение и поддержку дымовых тестов, возможно, следует подумать о покупке такого инструмента. Если уговорить начальника приобрести коммерческий ин$ струмент не получается, можете использовать приложение Tester из главы 16, за$ писывающее ввод мыши и клавиатуры в файл JScript или VBScript, который затем можно воспроизвести.

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

Работу над программой установки

следует начинать немедленно

Начинайте работать над программой установки сразу же после начала проекта. Это первая часть вашего приложения, которую видят пользователи. Слишком многие программы оставляют плохое первое впечатление, показывая, что програм$ ма установки была создана в последнюю минуту. Если вы начнете работу над про$ граммой установки как можно раньше, у вас будет время на ее тестирование и отладку. Разработав ее на ранней стадии проекта, вы сможете включить ее в ды$ мовой тест. Это позволит вам провести ее многократное тестирование, а ваши тесты еще на один шаг приблизятся к имитации того, как пользователи будут работать с программой.

Соседние файлы в предмете Программирование на C++