Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Основні параметри виведення



Введення

    Почати опис можливостей продукту Rational Purify хочеться перефразуванням одного дуже відомого вислову:  «з  точністю до  мілліБАЙТА ». Дане порівняння не  випадково, адже саме цей продукт спрямований на  вирішення всіх проблем, пов'язаних з  витоками пам'яті. Ні для кого не  секрет, що  багато програмних продуктів поводять себе  «Не  надто скромно », замикаючи на  себе під  час роботи всі  системні ресурси без  великої на то необхідності. Подібна ситуація може виникнути внаслідок небажання програмістів доводити створений код  «до  розуму », але  частіше подібне відбувається не з-за ліні, а  через неуважність. Це зрозуміло - сучасні темпи розробки ПЗ в умовах найжорстокішого пресингу з  боку конкурентів не  дозволяють приділяти занадто багато часу оптимізації коду, адже для  цього необхідні і  висока кваліфікація, і  наявність достатньої кількості ресурсів проектного часу. Як мені бачиться, маючи в  своєму розпорядженні надійний інструмент, який би сам в процесі роботи над  проектом вказував на всі чорні діри в  використанні пам'яті, розробники почали б його повсюдне впровадження, підвищивши надійність створюваного ПЗ. Адже і  тут ні для кого не  секрет, що в більшості складних проектів першочергове завдання, що стоїть перед розробниками полягає в  заміщенні стандартного оператора  «new» в  С ++, так як він НЕ зовсім адекватно себе поводить при  розподілі пам'яті.
    Ось на створенні \ написанні власних велосипедів і  дозволить заощадити Purify.

    Загальні можливості по  управлінню Purify схожі з  Quantify, за  винятком специфіки самого продукту. Тут також можна тестувати багатопотокові програми, також можна робити  «зліпки» пам'яті під  час тестування програми.

    Особливості використання цього додатка стосуються специфікою відловлюючих помилок і  способом видачі інформації.
    Інформація видається в  вигляді списку, з  найменуванням знайденої помилки  або попередження. При розгортанні списку з  конкретною помилкою виводиться додатковий набір даних, що характеризують помилку.



Основні параметри виведення

· Address.  IP адреса модуля, в якому виявлено помилку або попередження;

· Error Location.  Опис модуля з помилкою. В випадку тестування модуля з вихідними текстами, то в даному полі можна переглянути фрагмент коду, який викликав появу помилки;

· Allocate Location.  Різновид «Error Location », показує фрагмент коду, в якому був розподілений блок пам'яті, робота з яким, призвела до помилки

    Робота з Purify можлива як при наявності вихідних текстів і налагоджувальної інформації, так і без неї. В разі відсутності debug-інформації аналіз помилок ведеться тільки по ip-адресах. Так само як і в випадку з Quantify, можливий детальний перегляд функцій з dll-бібліотек. В цьому випадку наявність налагоджувальної інформації не є необхідністю.

Повідомлення про   помилки та   попередження

    Для того, щоб мати уявлення про  можливості продукту, опишемо те, які помилки і  потенційні помилки можуть бути присутніми в  тестованому додатку.

    Відзначимо різницю між помилкою і  потенційної помилкою і  опишемо:

· Помилка - Доконаний факт нестабільної  або некоректної роботи програми, призводить до  неадекватних дій додатка  або системи. Прикладом подібної помилки можна вважати вихід за  межі масиву  або спроба запису даних за 0 адресою;

· Потенційна помилка  - в додатку є фрагмент коду, який при нормальному виконанні не призводить до помилок. Помилка виникає тільки в разі збігу обставин, або не проявляє себе ніколи. До даної категорії можна віднести такі особливості, як ініціалізація масиву з ненульової адреси, скажімо, є масив на 100 байт, але кожен раз звернення до нього виробляється з 10 елемента. В цьому випадку Purify вважає, що є потенційний витік пам'яті розміром в 10 байт.

    Природно, що  подібна поведінка може бути викликана специфікою додатка, наприклад, так  поводитися може текстовий редактор. Тому в  Purify застосується поділ інформації на  помилки і  потенційні помилки  (які  можна сприймати як  специфіку).

    Список помилок і  потенційних помилок досить об'ємний і  постійно поповнюється. Коротко опишемо основні повідомлення, що виводяться після тестування:

· Array Bounds Read  Вихід за межі масиву при читанні;

· Array Bounds Write  Вихід за межі масиву при записі;

· Late Detect Array Bounds Write  Повідомлення вказує, що програма записала значення перед початком або після кінця розподіленого блоку пам'яті;

· Beyond Stack Read  Повідомлення вказує, що функція в програмі збирається читати поза поточного покажчика вершини стека;

· Freeing Freed Memory  Спроба звільнення вільного блоку пам'яті;

· Freeing Invalid Memory  Спроба звільнення некоректного блоку пам'яті;

· Freeing Mismatched Memory  Повідомлення вказує, що програма пробує;

· Free Memory Read  Спроба читання вже звільненого блоку пам'яті;

· Free Memory Write  Спроба запису вже звільненого блоку пам'яті;

· Invalid Handle  Операції над неправильним дескриптором;
Handle In Use Індикація витоку ресурсів. Неправильна індикація дескриптора;

· Invalid Pointer Read \ Write  Помилка при читанні \ записі з недоступного блоку пам'яті;

· Memory Allocation Failure  Помилка в запиті на розподіл пам'яті;

· Memory Leak  Витік пам'яті;

· Potential Memory Leak  Потенційний витік пам'яті;

· Null Pointer Read  Спроба читання з нульової адреси;

· Null Pointer Write  Спроба запису в нульовий адрес;

· Uninitialized Memory Copy  Спроба копіювання непроініціалізірованного блоку;

· UMR: Uninitialized Memory Read  Спроба читання непроініціалізірованного блоку.

    Попередження і помилки зручно групувати за певними ознаками, щоб легше можна було відшукати потрібне попередження і відкинути непотрібні.

    Відзначимо категорії і  приналежність до них різних повідомлень:

· Allocation And   deallocation.  Робота з пам'яттю;

· DLL messages.  Інформаційні повідомлення по зовнішнім бібліотекам;

· Invalid handles.  Неправильний дескриптор;

· Invalid pointers.  Неправильний покажчик;

· Memory leaks.  Витік пам'яті;

· Parameter errors.  Помилка параметра;

· Stack errors.  Помилка при роботі зі стеком;

· Unhandled exception.  Виняток;

· Uninitialized memory.  Використання непроініціалізірованного блоку пам'яті.

    Багато статичних помилок можуть виловлювати компілятори на етапі розробки програмного модуля або програми. На цьому етапі переваги Purify НЕ дуже видно.

    Всі механізми аналізу помилок відкриваються при  виконанні додатка, при  динамічно мінливих умовах.

    Розглянемо більш докладно список відловлювальних помилок, визначивши їх  приналежність до  категорій з  прикладами на  C ++ / C:

    ABR: Array Bounds Read.  Вихід за  межі масиву при  читанні.
    Відома хвороба всіх розробників - неправильно поставлена умова в  циклі. Відповідно, помилка, яка має місце бути в  програмі, пов'язана з  читанням зайвої інформації, може проявити себе, а  може і НЕ проявити. Але вона є потенційною помилкою.

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [5]; // Виділяємо пам'ять під   масив з 5 символів

ptr [0] = 'e';
ptr [1] = 'r';
ptr [2] = 'r';
ptr [3] = 'o';
ptr [4] = 'r';
for (Int  I = 0; i ≤ 5; i ++) {
// Помилка, при   i = 5 - вихід за   межі масиву
cerr < <  «ptr [" < < i  < < " ] ==" < < ptr [i] < < '\ n';
}
delete [] ptr;
return (0);
}

    ABW: Array Bounds Write.  Вихід за  межі масиву при записі.
    Імовірність того, що  додаток може неадекватно поводитися з-за цієї помилки більш висока, так як запис за  адресою, що перевищує розмір блоку, викликає виняток.

    Відзначимо, що  пам'ять можна визначити статично, масовому, як  показано в  прикладі. А можна динамічно  (наприклад, виділивши блок пам'яті по  ходу виконання додатка).

    За замовчуванням, Purify успішно справляється тільки з  динамічним розподілом, чітко виводячи повідомлення про  помилку. В випадку статичного розподілу, все  залежить від розмірів «Купи» і  налаштувань компілятора.

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr  = New  Char [5]; // Виділяємо пам'ять під   масив з   5 символів
for (Int  I = 0; i ≤ 5; i ++) {
// Помилка, при   i = 5   - вихід за   межі масиву
ptr [i] = '! ';
cerr < < " ptr [" < < i  < < " ] ==  «< < ptr [i] < < '\ n';   // ABW + ABR   When I is 5
}
delete [] ptr;
return (0);
}

    BSR: Beyond Stack Read.  Повідомлення вказує, що  функція в  програмі збирається читати поза  поточного покажчика вершини стека

Категорія: Stack Error

#include < windows.h>
#include < iostream.h>
#define A_NUM 100
char * create_block  (void)
{
char block [A_NUM]; // Помилка: масив повинен бути статичним
for (Int  I = 0; i < A_NUM; i ++) {
block [i] = '! ';
}
return (Block); // Помилка: невідомо, що   повертати
}

int main  (int, char **)
{
char * block;
block = create_block  ();
for (Int  I = 0; i < A_NUM; i ++) {
// BSR: немає   гарантії, що   елементи з   «create_block" до сих пір знаходяться в   стеку

cerr < <  «element  # " < < i < < «Is  " < < block [i] < < '\ n';
}
return (0);
}

    FFM: Freeing Freed Memory.  Спроба звільнення вільного блоку пам'яті.

    В великому додатку важко відстежити момент розподілення блоку і  момент звільнення. Дуже часто методи реалізуються різними розробниками, і, відповідно, можлива ситуація, коли розподілений блок пам'яті звільнюєтьсядвічі на  різних ділянках програми.

Категорія: Allocations And   deallocations

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr1 = New  Char;
char * ptr2 = ptr1; // Помилка: повинен дублювати об'єкт, а НЕ копіювати покажчик
* ptr1 = 'a';
* ptr2 = 'b';
cerr < < " ptr1" < <  «is  " < < * ptr1 < < '\ n';
cerr < <  «ptr2" < <  «is  " < < * ptr2 < < '\ n';
delete ptr1;
delete ptr2; // Помилка - звільнення незайнятої пам'яті
return (0);
}

    FIM: Freeing Invalid Memory.  Спроба звільнення некоректного блоку пам'яті.

    Розробники часто плутають прості статичні значення і  покажчики, намагаючись звільнити те, що НЕ звільняється. Компілятор  завжди здатний проаналізувати і  нейтралізувати даний вид  помилки.

Категорія: Allocations And   deallocations

#include < iostream.h>

int main  (int, char **)
{
char a;
delete [] & a; // FIM: в   динамічній пам'яті немає   об'єктів для   знищення
return (0);
}

    FMM: Freeing Mismatched Memory.  Повідомлення вказує, що  програма пробує звільняти пам'ять з  неправильним ВИКЛИКОМ API  для того типу пам'яті.

Категорія: Allocations And   deallocations

#include < windows.h>

int main  (int, char **)
{
HANDLE heap_first, heap_second;
heap_first = HeapCreate  (0, 1000, 0);
heap_second = HeapCreate  (0, 1000, 0);
char * pointer =  (char  *) HeapAlloc  (heap_first, 0, sizeof  (int));
HeapFree  (heap_second, 0, pointer);
// Помилка - в   другий купі НЕ   виділялася пам'ять

HeapDestroy  (heap_first);
HeapDestroy  (heap_second);
return (0);
}

    FMR: Free Memory Read.  Спроба читання вже  звільненого блоку пам'яті

    Все та ж проблема з  покажчиком. Блок розподілений, звільнений, а  потім, в  відповідь на  подію, по  покажчику починають записуватися (Або читатися) дані.

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [2];
ptr [0] = '! ';
ptr [1] = '! ';
delete [] ptr; // Помилка - звільнення виділеної пам'яті
for (Int  I = 0; i < 2; i ++) {
// FMR: помилка - спроба читання звільненій пам'яті
cerr < <  «element  # " < < i < < «Is  " < < ptr [i] < < '\ n';
}
return (0);
}

    FMW: Free Memory Write.  Спроба запису вже  звільненого блоку пам'яті

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [2];
ptr [0] = '! ';
ptr [1] = '! ';
delete [] ptr; // спеціально звільняємо виділену пам'ять
for (Int  I = 0; i < 2; i ++) {
ptr [i] * = 'A';   // FMR + FMW: пам'ять для   * ptr вже   звільнена
cerr < <  «element  # " < < i < < «Is  " < < ptr [i] < < '\ n'; // FMR
}
return (0);
}

    HAN: Invalid Handle.  Операції над  неправильним дескриптором

Категорія: Invalid handles

#include < iostream.h>
#include < windows.h>
#include < malloc.h>
Int  Main  (int, char **)
{
Int  I = 8;
(void) LocalUnlock ( (HLOCAL) i); // HAN: i   - НЕ   є описувачем  об'єкта пам'яті
return (0);
}

    HIU: Handle In   Use.  Індикація витоку ресурсів. Неправильна індикація дескриптора.

#include < iostream.h>
#include < windows.h>
static long GetAlignment  (void)
{
SYSTEM_INFO desc;
GetSystemInfo  (& desc);
return (Desc.dwAllocationGranularity);
}
Int  Main  (int, char **)
{
const long alignment = GetAlignment  ();
HANDLE handleToFile = CreateFile ( «File.txt",
GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if  (handleToFile  == INVALID_HANDLE_VALUE) {

cerr < <  «Помилка  відкриття, створення файлу \ n ";
return (1);
}
HANDLE handleToMap = CreateFileMapping  (handleToFile, NULL, PAGE_READWRITE, 0, alignment,  «mapping_file" );
if  (handleToMap  == INVALID_HANDLE_VALUE) {
cerr < <  «Unable to create actual mapping \ n ";
return (1);
}
char * ptr = (Char  *) MapViewOfFile  (handleToMap, FILE_MAP_WRITE, 0, 0, alignment);

if  (ptr  == NULL) {
cerr < <  «Unable to Map  Into Address Space \ n ";
return (1);
}
strcpy  (ptr,  «hello \ n" );
// HIU: handleToMap до сих пір доступний і   описує існуючий об'єкт
return (0);
}

    IPR: Invalid Pointer Read.  Помилка звернення до  пам'яті, коли програма намагається зробити читання з  недоступної області.

Категорія: Invalid pointers

#include < iostream.h>

#include < windows.h>
Int  Main  (int, char **)
{
char * pointer =  (char  *) 0xFFFFFFFF;
// Помилка   - покажчик на   зарезервовану область пам'яті

for (Int  I = 0; i < 2; i ++) {
// IPR: звернення до   зарезервованої частини адресного простору
cerr < <  «pointer [" < < i  < < " ] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    IPW: Invalid Pointer Write.  Помилка звернення до  пам'яті, коли програма намагається зробити запис з  недоступної області

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * pointer =  (char  *) 0xFFFFFFFF;
// Помилка   - покажчик на   зарезервовану область пам'яті

for (Int  I = 0; i < 2; i ++) {
// IPW + IPR: звернення до   зарезервованої частини адресного простору
pointer [i] = '! ';
cerr < <  «ptr [  «< < i < < «] ==  «< < ptr [i] < < '\ n';
}
return (0);
}

    MAF: Memory Allocation Failure.  Помилка в  запиті на  розподіл пам'яті. Виникає в  випадках, коли проводиться спроба розподілити занадто великий блок пам'яті, наприклад, коли вичерпано файл підкачки.

Категорія: Allocations And   deallocations

#include < iostream.h>
#include < windows.h>
#define BIG_BLOCK 3000000000   // розмір блоку
Int  Main  (int, char **)
{
char * ptr = New  Char [BIG_BLOCK / sizeof  (char)];
// MAF: занадто великий розмір для   розподілу
if  (ptr  == 0) {
cerr < <  «Failed to allocating, AS  Expected \ n ";
return (1);
} else {
cerr < <  «Got  " < < BIG_BLOCK < <  «bytes  @ " < <  (Unsigned  Long) ptr < < '\ n';
delete [] ptr;
return (0);
}
}

    MLK: Memory Leak.  Витік пам'яті

    Поширений варіант помилки. Багато сучасних програм грішать тим, що НЕ віддають системі розподілені ресурси по  закінченні своєї роботи.

Категорія: Memory leaks

#include < windows.h>
#include < iostream.h>
Int  Main  (int, char **)
{
(Void) New  Int [1000];
(void) New  Int [1000];
// результат втрати пам'яті
return (0);
}

    MPK: Potential Memory Leak.  Потенційний витік пам'яті
    Іноді виникає ситуація, в  якій необхідно провести ініціалізацію масиву не з нульового елемента. Purify вважає це  помилкою. Але розробник, який пише горезвісний текстовий редактор може ініціалізувати блок пам'яті не з нульового елемента.

Категорія: Memory leaks

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
static int  * pointer = New  Int [100000];
pointer + = 100; // MPK: втратили початок масиву
return (0);
}

    NPR: Null Pointer Read.  Спроба читання з  нульової адреси
    Більше  за все програм на  С \ С ++. Дуже часто себе помилка проявляє при  динамічному розподілі пам'яті додатком, так як НЕ всі розробники ставлять умову на  отримання блоку пам'яті, і  виникає ситуація, коли система не  може видати блок зазначеного розміру і  повертає нуль. За через відсутність умови розробник як НЕ в ніж НЕ бувало починає проводити операції над  блоком, адреса в  пам'яті якого 0.

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int
Main  (int, char **)
{
char * pointer =  (char  *) 0x0;   // вказівник на   нульовий адрес
for (Int  I = 0; i < 2; i ++) {
// NPR: спроба читання з  нульового адреси
cerr < <  «pointer [" < < i < < «] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    NPW: Null Pointer Write.  Спроба запису в  нульовий адрес

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int
Main  (int, char **)
{
char * pointer =  (char  *) 0x0;   // вказівник на   нульовий адрес
for (Int  I = 0; i < 2; i ++) {
// NPW: помилка доступу
pointer [i] = '! ';
cerr < <  «pointer [  «< < i < < «] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    UMC: Uninitialized Memory Copy.  Спроба копіювання непроініціалізірованного блоку пам'яті

Категорія: Unitialized memory

#include < iostream.h>
#include < windows.h>
#include < string.h>

int main  (int, char **)
{
int  * pointer = New  Int [10];
Int  Block [10];
for (Int  I = 0; i < 10; i ++)
{
pointer [i] = block [i];   // UMC попередження
cerr < < block [i] < < " \ n";

}

delete [] pointer;
return (0);
}

    UMR: Uninitialized Memory Read.  Спроба читання непроініціалізірованного блоку пам'яті

Категорія: Unitialized memory

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * pointer = New  Char;
cerr < <  «* pointer is  " < < * pointer < < '\ n';
// UMR: pointer вказує на   непроініціалізірованний елемент
delete [] pointer;
return (0);
}

Робота з   фільтром

    Щоб не  захаращувати користувальницький інтерфейс зайвими даними, в  Purify передбачена система гнучких фільтрів.
    Система фільтрів Purify здатна регламентувати тип  помилок і  попереджень та  помилок  (угруповання  проводиться по  категоріям) до  програми, але і число досліджуваних зовнішніх модулів  (щоб  розробник міг  концентруватися тільки на  помилках власного модуля). Таким чином можливе створення універсальних фільтрів з  осмисленими іменами, які обмежують потік інформації. Число створюваних фільтрів нічим не  обмежена.

    Фільтри створюються і  призначаються і  модифікуються через верхнє меню  (View → CreateFilter і  View → FilterManager). За замовчуванням Purify виводить всі  повідомлення і  попередження.

    Малюнок показує зовнішній вигляд  вікна створення фільтра  (View → CreateFilter). Тут ми  маємо можливість по  вибору повідомлень, які потрібно фільтрувати.

    Пункт General - управляє ім'ям фільтру і  коментарем, його  супроводжуючим, Source - визначає місце розташування вихідних файлів, для  яких необхідно вивести повідомлення. Підхід використовується в тому випадку, коли відбувається виклик одного модуля з  іншого, щоб обмежити кількість інформації в  звіті.
    Наступний малюнок демонструє вид  вікна налаштувань фільтрів. Тут є можливість по  активації \ деактваціі фільтрів і  модулів.

    Вище згадувалося, що  Purify НЕ  обмежує число фільтрів. Слід розуміти, що НЕ обмежується НЕ  тільки загальне число фільтрів, але і їх кількість на  один протестований додаток.

    Обмеження по  модулям, яке також можна виставити в  даному діалозі, визначає число зовнішніх модулів, попередження від  яких з'являються в  звіті.













































































































































































































































API

    Rational Purify  також має ряд  функцій інтерфейсу, впливаючи на  які, розробник на  етапі створення програми може користуватися всіма благами, що надаються даним додатком.
    Опишемо основні функції інтерфейсу з  короткою характеристикою, розділивши попередньо всі  функції по  основних групах:

Функції установки статусу розподілених блоків:

· PurifyMarkAsInitialized.  Встановлює позначку на вказаний блок, роблячи його поміченим, як проініціалізований;

· PurifyMarkAsUninitialized.  Ставить прапор ініціалізації;

Функції тестування станів розподілених блоків

· PurifyAssertIsReadable.  Перевіряє, чи доступний блок пам'яті для читання;

· PurifyAssertIsWritable.  Перевіряє, чи доступний блок пам'яті для запису;

· PurifyIsInitialized.  Перевіряє, проініціалізований блок пам'яті чи ні;

· PurifyIsReadable.  Перевіряє блок пам'яті на можливість читання;

· PurifyIsWritable.  Перевіряє блок пам'яті на можливість запису;

Функції, що визначають руйнування

· PurifySetLateDetectScanCounter.  Визначає лічильник сканування купи. Підраховує кількість операцій. За замовчуванням, Purify сканує пам'ять через кожні 200 операцій з пам'яттю, або кожні 10 секунд;

· PurifySetLateDetectScanInterval.  Визначає інтервал пошуку купи. За замовчуванням - 10 секунд;

· PurifyHeapValidate. Примусово перевіряє пам'ять на наявність помилок;

Функції, що визначають витоку пам'яті

· PurifyAllInuse.  Повертає значення, що визначає кількість використаної пам'яті;

· PurifyClearInuse.  Повертає значення, яке показує кількість пам'яті, розподіленої після останнього дзвінка PurifyClearInuse або PurifyNewInuse;

· PurifyAllLeaks.  Повертає число знайдених витоків у пам'яті. Знаходить як прямі витоки пам'яті, так і непрямі;

· PurifyClearLeaks.  Визначає число звільнених блоків пам'яті за час останнього звернення до PurifyClearLeaks або PurifyAllLeaks;

· PurifyNewLeaks.  Визначає число нових витоків пам'яті за час останнього звернення до PurifyNewLeaks або PurifyClearLeaks.

Збереження даних і   експорт

    Purify  дозволяє зберігати результати тестування  (file → save copy as) в  чотирьох різних уявленнях, що дозволяють найбільш ефективним чином отримати інформацію про  хід тестування.

Розглянемо варіанти збереження:

· Purify Error unfiltered.  Зберігає дані про тестуванні в вигляді «Як є »без фільтрів;

· Purify error filtered.  Зберігає дані про тестування з застосованими фільтрами;

· Text expended.  Зберігає дані в текстовому вигляді про тестування в розширеному поданні (з виведенням знайдених помилок, з коротким описом);

· Text view.  Зберігається тільки згадка про знайдені помилки, без додаткового опису.

    При встановленому MS Outlook, можливо відправлення звіту поштою через пункт file → send з верхнього меню Purify.


Параметри тестування

    Перед виконанням тестованої програми, можливо, задати додаткові налаштування, які зможуть налаштувати Purify на  ефективне тестування.

    Запуск програми проводиться точно також як і в випадку з  Quantify  (по  F5  або file → Run). Параметри налаштування знаходяться пункті Settings, вікна, що з'явилося.

Перша сторінка діалогу представлена ​ ​ на  малюнку

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

· Report AT   Exit.  Дана група дозволяє отримувати більш детальну інформацію про всіх покажчиках і блоках пам'яті, що не приводили до помилок пам'яті. За замовчуванням, Purify виводить звіти тільки по тим блокам, які були розподілені, але НЕ були звільнені. В більшості випадків такий підхід виправданий, так як зазвичай розробника цікавлять саме помилки. Інші пункти активізують по мірі необхідності, коли потрібно мати загальне уявлення про використання пам'яті тестованим додатком;

· Error Suppretion.  Група визначає ступенем детальності виведеної інформації.
За замовчуванням, активований пункт «Show First Message Only ». В цьому випадку по закінченні тестування, Purify виводить скорочений звіт по модулям, тобто, якщо в одному модулі знайдено 10 витоків пам'яті, то інформація про витоки на основному екрані буде описувати тільки ім'я помилки, число блоків і ім'я модуля. Тобто ми отримуємо узагальнену інформацію помилок у блоці. В разі необхідності отримання окремого звіту по кожному окремому блоку, відключаємо даний пункт.

· Call Stack Length.  Визначає глибину стека;

· Red Zone Length.  Управляє числом байтів, яке вбудовується в код тестованої програми при операціях пов'язаних з розподілом пам'яті. Збільшення числа сприяє кращому збору інформації, але істотно гальмує виконання додатка;

    Закладка PowerCheck  дозволить налаштувати рівень аналізу кожного окремо взятого модуля. Існує два способи інструментації тестованої програми: Precise і Minimal. В першому випадку проводиться детальне інструментування коду, але при цьому модуль працює відносно повільно. Під другому випадку, проводиться коротке інструментування, при якому Purify вносить в модуль менше налагоджувальної інформації, і, як наслідок, здатна відловити менше число помилок. Останній підхід виправданий, коли додаток викликає масу зовнішніх бібліотек від третіх фірм, котрі не будуть піддаватися правці.


Введення

    Основне призначення продукту - виявлення ділянок коду, пропущеного при  тестуванні додаткиа- перевірка області охоплення коду.

    Очевидно, що при тестуванні розробнику  або тестувальника НЕ  вдасться перевірити працездатність всіх функцій. Також неможливо за  один прохід тестування виконати додаток з  урахуванням всіх умовних розгалужень.

    За вимогам на  розробку програмного коду, програміст повинен надати для  функціонального тестування стабільно працюючеийдодаток  або модуль, без  витоків пам'яті і  повністю протестований.

    Поняття  «повністю  протестований »визначає керівництво компанії в  числовому, відсотковому значенні. Тобто, при  оформленні вимог зазначено, що  область охоплення коду 70%. Відповідно, при  досягненні даної цифри подальші перевірки коду можна вважати недоцільними. Звичайно, питання області охоплення, дуже складний і  неоднозначний. Єдиною втіхою може служити те, що  100% області охоплення в  великих проектах не  буває.

    З  трьох розглянутих інструментів тестування PureCoverage можна вважати найбільш простим, так як інформація їм  надається - це  перегляд вихідного тексту програми, де  вказано скільки разів  здійснилася та  чи інша рядок в  додатку.

Особливості запуску

    Запуск програми ведеться точно таким  же чином, як і в інших випадках. Тут нового нічого немає. З  особливостей можна відзначити те, що  тестувати можна тільки той  додаток, що містить зневадження. Дана особливість виділяє PureCoverage з  лінійки інструментів тестування для  розробників, які можуть тестувати як код з налагоджування, так і без неї.

Робота з   PureCoverage

    За принципом роботи PureCoverage злегка нагадує Quantify: також підраховує кількість викликів функцій. Правда, одержувана статистика не  настільки вичерпна як в Quantify (В візуальному відношенні), але для перевірки області охоплення коду цілком і  цілком придатна.

Система звітності представлена 4 різними видами звітів:

· Coverage Browser.  Основне вікно перегляду, дозволяє переглядати протестований додаток по модулям або по файлам. Видає статистику про наявність пропущених рядків;

· Function List.  Видає звіт по функціям;

· Annotated Source.  Перехід до режиму перегляду початкового тексту;

· Run Summary.  Загальна інформація про протестованому додатку;

API

    Як і Quantify з  Purify, даний інструмент має функції розширення інтерфейсу. Розглянемо їх  короткий опис.

· CoverageAddAnnotation.  Дозволяє додати словесний опис, що супроводжує тестування. Інформація, задана розробником цієї функцією може бути залучена з пункту «details» меню тестування і доступна в LOG-файлі. На її основі, тестер може згодом використовувати особливі умови тестування;

· CoverageClearData.  Очищає незбережені дані. Використовується для обнулення (ініціалізації);

· CoverageDisableRecordingData. Заборона на запис даних про хід тестування. Продовження запису не можливо. Використовується для завершення процесу тестування;

· CoverageIsRecordingData.  З'ясовує чи проводиться процес запису даних про хід тестування. Використовується для визначення поточного статусу;

· CoverageIsRunning.  Оприділяє, чи запущений інтсрумент тестування;

· CoverageSaveData.  Збереження тестових даних. Використовується для отримання зліпків. Зазвичай цю функцію зручно викликати перед і після блоку розгалуження в програмі;

· CoverageStartRecordingData.  Початок процесу запису тестових даних;

· CoverageStopRecordingData.  Закінчення процесу запису тестових даних;

Збереження даних і   експорт

    Дані з  інструменту тестування зберігаються в  текстовому файлі  (як і в двох попередніх випадках). Текстовий формат видачі інформації робить можливим включати різні обробники звітів засновані на  скриптових мовах  (наприклад, при  допомозі Perl, можна  «вивудити» специфічні поля з  текстового звіту і  помістити їх в засіб документування, отримавши звіт).
Приклад фрагмента звіту наведено нижче:

CoverageData WinMain Function D: \ xp \ Rational \ Coverage \ Samples \ hello.c D: \ xp \ Rational \ Coverage \ Samples \ hello.exe 0 1 1 100.0 5 5 10 50.00 36 1

SourceLines D: \ xp \ Rational \ Coverage \ Samples \ hello.c D: \ xp \ Rational \ Coverage \ Samples \ hello.exe
LineNumber LineCoverage
18.1 0
23.1 0
26.1 0
26.1 0
27.1 0
27.1 0

PureCoverage також як і Quantify може переносити табличні дані в  Microsoft Excel.









Підсумок

    Даний інструмент є найбільш простим з  трьох. Основна його  відмінність - неможливість роботи з  додатками, в  яких відсутня налагоджувальна інформація. З  достоїнств відзначимо можливість одночасного запуску спільно з  Purify, що  дозволяє отримати звіти по  витокам пам'яті і  підрахунок числа рядків за  один прохід в  тестуванні, що  суттєво економить час при  налагодженні і  тестуванні.

Додаткові можливості засобів тестування для   розробників

Способи запуску

Всі інструментальні засоби можуть працювати на 3 рівнях виконання:

· Виконання з меню операційної системи. Використовується в більшості випадків, як розробниками так і тестувальниками. Останніми частіше, так як у тестувальників може не бути середовища розробки;

· Виконання з середовища розробки (якщо є інтеграція з конкретним засобом). Застосовується в тих випадках, коли інструмент має інтеграцію зі засобом розробки. Представляється найбільш зручним варіантом роботи для розробників;

· Виконання з командного рядка. Застосовується в специфічних ситуаціях: при інтеграції з засобами автоматизованого тестування функціонального інтерфейсу, а також при тестуванні особливих додатків (таких як сервіси Win32).

Типи тестів

    Тести продуктивності  (Performance  Tests) дозволяють визначити, чи працює багатокористувацька система в  відповідності з  необхідних стандартів при  зміненні навантажень. В результаті виконання тестів вимірюються часи відгуку системи на  якійсь із  запитів, і на основі зібраної статистичної інформації робляться висновки про  характеристиках системи. Тести продуктивності виконуються за  допомогою програми LoadTest. При цьому тестуванні типово використовується навантаження сервера великою кількістю віртуальних користувачів. Наприклад, ви  можете встановити таймер для  одного VU, щоб визначити, скільки часу займе виконання запиту, коли тисячі інших VU  посилають запити на той же самий сервер в то же самий час. Термін 'тести продуктивності' включає навантажувальні, стресові, конкуруючі і  конфігураційні тести. Сукупність цих тестів дозволяє прискорити цикл тестування продуктивності і  досягти значущих і  точних результатів.

    Тестування навантаження  (Load  Tests) виконується тоді, коли потрібно визначити час відгуку серверів  або клієнтських додатків при  навантаженню, що змінюється. Тестування навантаження також використовується тоді, коли потрібно обчислити, яку максимальну кількість транзакцій може виконати сервер за  певний часовий відрізок. Якщо клієнт / серверна система використовує розподілену архітектуру  або засоби балансування навантаження - тестування навантаження може бути використано для  того, щоб перевірити правильність обраних методів для  балансування  або конструювання системи.

    Тестування навантаження виконується як з використанням режиму тільки віртуальних користувачів, коли вимірюється час відгуку тільки серверної частини  або комбінації віртуальних користувачів і  користувачів графічного інтерфейсу для  вимірювання часу відгуку системи для  конкретного клієнтського додатку.

    Стресове тестування  (Stress  Test)  - це  перевірка роботи системи в  екстремальних умовах, тобто, коли випробовувана система штучно ставиться в  умови, які можуть призвести до  збою в  роботі як  клієнтської  або серверної частини додатків, так і всієї системи в  цілому.

Способів організації стресового тестування може бути безліч, наприклад:

· тривала робота клієнт / серверних додатків.

· виконання великої кількості транзакцій

· одночасне звернення до сервера великої кількості користувачів виконують одну й ту ж операцію або комбінацію операцій віртуально в той же самий момент часу.

· заповнення клієнтських форм свідомо неправильними або недостатніми даними і виконання транзакцій з цими даними.

· створення умов для роботи тестованої системи з недостатньою кількістю пам'яті або поділюваних системних ресурсів.

    Стресове тестування дозволяє вам  бути впевненими в  тому, що  ваш клієнтський додаток  або сервер будуть зберігати працездатність незважаючи на  несприятливий розподіл ресурсів в  комп'ютерній системі.

    Конкуруюче тестування  (Contention  Test) виконується як  комбінація GUI і VU на одному або декількох комп'ютерах, для  того щоб емулювати дійсне багатокористувацьке оточення. Наприклад, можна створити тест, коли кілька GUI  користувачів і  безліч віртуальних користувачів в  один і  той же час будуть звертатися до тієї ж самійої бази даних для  виявлення проблем в  управлінні багатозадачністю  або блокування. Без  автоматизованого засобу тестування такі тести, що вимагають точної синхронізації дій великої кількості користувачів, виконати практично неможливо.

    Засоби тестування дозволяють створювати дуже складні сценарії багатокористувацького тестування з  залученням в  цей процес декількох комп'ютерів з  великою кількістю GUI і VU  користувачів. При цьому, наприклад, користувачі одного з  комп'ютерів будуть чекати результатів виконання дій користувачами іншого комп'ютера і  тільки потім вступати в  процес тестування. Наприклад, користувачі на  одному з  комп'ютерів додають записи в  базу, а на другом чекають завершення виконання цього скрипта, а  потім читають внесення запису і  т.п.

    Конфігураційне тестування  (Configuration  Testing). Кожен комп'ютер користувача може мати різну суміш апаратних і  програмних особливостей, які створюють ризик того, що  створюване програмне забезпечення буде працювати на  одному з  них, а на одним не  буде. Знизити ймовірність виникнення таких ситуацій можна застосуванням конфігураційних тестів, коли один раз  створені скрипти для  GUI і VU  користувачів будуть виконуватися на  комп'ютерах з  різними OS  або конфігураціями програмних і  апаратних засобів. Наприклад, якщо ви використовуєте кілька типів мережевих карт, ви  можете виконати серію тестів для  кожної з  них з тим, щоб визначити, яка володіє кращими характеристиками.

    Розподілене функціональне тестування  (Distributed  Functional Testing).

    Повний цикл функціонального тестування складного клієнт / серверного додатка може зажадати виконання великої кількості скриптів. При цьому GUI  скрипти будуть послідовно виконуватися з  допомогою програми Robot на  одному з  комп'ютерів в  протягом дуже довгого часу. PerformanceStudio дозволяє значно прискорити процес тестування за  рахунок залучення в  процес тестування більшого числа комп'ютерів і  розподілу між ними GUI  скриптів для  виконання. Все управління процесом тестування в  даному випадку бере на  себе програма LoadTest, яка збирає інформацію ході процесу тестування, розподіляє скрипти між вивільненими комп'ютерами та в випадку втрати мережевого з'єднання з  яким-небудь з  них, передає виконуваних ним  скрипт на  виконання наступної звільнилася машині.

Типи записи тестів

    Виконувана PerformanceStudio інтелектуальний запис на  рівні пакетів гарантує, що  скрипти, які ви  записуєте, точно відображають трафік між клієнтами і  серверами, незважаючи на  швидкість передачі даних.

    Засоби тестування IBM  Rational підтримують три  режими інтерактивного запису скриптів:

    API  - Записує API  виклики з  клієнтських додатків і  клієнтських бібліотек до  серверів. API  режим запису являється рекомендованим підходом для  всіх клієнтів, що працюють на  платформі Windows NT. В цьому режимі і  PerformanceStudio і  клієнтську програму обидва  встановлюються на  клієнтський комп'ютер.

    Network - записує трафік по  TCP / IP протоколу на  рівні мережного інтерфейсу. Цей тип  запису рекомендований тоді, коли покупець не  підтримує API  режим запису.

Proxy - в  цьому режимі записується той  же самий трафік, що і в режимі запису Network, але для передачі пакетів між клієнтом і  сервером використовується машрутізація через proxy комп'ютер. Цей спеціалізований тип  запису застосовується в  високошвидкісних мережах і  мережах з  комутаторами.

Введення в   Test Manager

Види тестів

    RUP  регламентує і  описує безліч різних видів тестів, фокусуючих увагу на  різних проектних проблемах.

    TestManager, будучи засобом планування тестування, відповідає за їх коректне виконання. Не буде зайвим нагадати, що  створенням скриптів  (бібліотеки  скриптів) займається Rational Robot, фізично здійснює запис і  відтворення скриптів. Отриманий набір скриптів перетвориться в  план тестування, а  потім в  сценарій тестування безпосередньо в  TestManager

Розглянемо основні види тестів з  RUP:

· функціональне тестування;

· тестування цілісності баз даних;

· тестування бізнес циклів;

· тестування користувальницького інтерфейсу;

· профілювання продуктивності;

· тестування навантаження;

· стресове тестування;

· об'ємне тестування;

· тестування управління доступом. Тестування безпеки;

· тестування відновлення після збоїв;

· конфігураційне тестування;

· інсталяційне тестування.

    Описані види тестів дозволять здійснити всебічне тестування програмного продукту. RUP регламентує всі види робіт, а також методику підготовки тестових наборів. В тому числі регламентуються такі параметри як: мета тестування, методика тестування, критерії тестування, а також визначаються особливі умови, необхідні для проведення всебічного тестування.

    Розглянемо докладно основні види тестів, додаткові умови тестування, вимоги до  тестів і  критерії завершення.

Функціональне тестування

    Функціональне тестування об'єкта-тестування планується і  проводиться на  основі вимог до  тестування, заданих на  етапі визначення вимог. В якості вимог виступають діаграми use-case, бізнес-функції і  бізнес-правила. Мета функціональних тестів полягає в  тому, щоб перевірити відповідність розроблених графічних компонентів встановленим вимогам.

    В основі функціонального тестування лежить методика  «чорного  ящика ". Ідея тестування зводиться до  того, що  група тестувальників проводить тестування, не  маючи доступу до  вихідних текстів тестованої програми. При цьому під  увагу приймається тільки вхідні вимоги і  відповідність їм  тестованим додатком.

    При необхідності (В відповідності до  обраної раніше стратегії тестування) можна скористатися на  етапі функціонального тестування підходом, званим «скляним  ящиком ». В режимі «Скляного  ящика »тестувальник повинен володіти мовою реалізації та  тестувати код  програми в  відповідності з  прийнятими стандартами на  розробку, наприклад такими, як  перевірка коду на  відсутність операторів переходу  (goto). Також на  тестувальника покладається відповідальність за  установку відповідності поточної розробки на  відповідність певним канонам програмування.

    На етапі функціонального тестування не  застосовується тестування  «скляного  ящика »в  чистому вигляді - використовується комбінація двох видів тестування. Підхід «скляного  ящика »для  функціонального тестування несе ряд  обмежень, і  здатний проводити тестування по  наступним категоріям:

· тест на продуктивність;

· тест на наявність помилок з пам'яттю;

· тест на покриття коду.

    Комбіноване тестування дозволить отримати тестувальникам на виході найбільш повний звіт про відповідність тестованої програми всім встановленим вимогам на графічний інтерфейс, продуктивність коду та його стійкість.

Мета тестування:

    Переконатися в  належному функціонуванні об'єкта тестування. Тестується правильність навігації по  об'єкту, а  також введення, обробку і  виведення даних.

Методика:

    Необхідно виконати  (програти) кожен з  use-case, використовуючи як  вірні значення, так і свідомо помилкові, для  підтвердження правильного функціонування, по  таким критеріям:

· продукт адекватно реагує на всі введені дані (виводяться очікувані результати в відповідь на правильно вводяться дані);

· продукт адекватно реагує на неправильно введені дані (з'являються відповідні повідомлення про помилки);

· кожне бізнес-правило реалізовано належним (встановленим) чином.

Критерії Завершення:

    Всі заплановані дії по  тестуванню виконані.

    Всі знайдені дефекти були відповідним чином оброблені  (документовані і поміщені в  базу дефектів).

Тестування цілісності даних і   баз   даних

Мета Тестування:
    Переконатися в  надійності методів доступу до  баз даних, в їх правильному виконанні, без  порушення цілісності даних.

Методика:
    Необхідно послідовно випробувати максимально можливе число способів звернення до  бази. Використовується підхід, при  якому тест складається таким чином, щоб  «навантажити» базу послідовністю, як  вірних значень, так і свідомо помилкових.

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

Критерії Завершення:

    Всі способи доступу функціонують, в  відповідності з  вимогами.

    Дії скрипта не  призводять до  втрати даних  або порушення цілісності бази,  або до  іншим неадекватних реакцій.



Тестування бізнес циклів

    Тестування Бізнес Циклів повинно емулювати дії, що виконуються в  проекті  протягом певного часового інтервалу. Період має бути визначений тривалістю в  один рік. Всі події, дії і  транзакції які імовірно будуть відбуватися  протягом цього періоду з  додатком, повинні бути відтворені. Включаються всі  денні, тижневі, місячні цикли та  події, які є чутливими до  дати.

Мета тестування:
    Перевірити вірність функціонування об'єкта тестування та  пов'язаних з ним процесів на  відповідність вимогам бізнес моделей і  розкладів.

Методика:
    Тестування буде моделювати кілька бізнес циклів, з  виконанням наступного:

1. тести, що застосовуються для перевірки функціонування об'єкта тестування, модифіковані для збільшення числа повторень виконання кожної функції програми, моделюванням роботи декількох користувачів протягом заданого тимчасового інтервалу;

2. всі функції, які працюють з датою або часом, коректно виконуються в будь-яких тимчасових інтервалах;

3. всі функції, виконувані в періодичних розкладах виконуються або викликаються в відповідних тимчасових інтервалах;

4. тестування включає використання правильних і неправильних дат для перевірки реакції програми

Критерії завершення:
    Всі заплановані тести виконані. Всі виявлені дефекти оброблені і задокументовані.

Тестування для користувача інтерфейсу

Мета Тестування:
    Перевірити вірність навігації по  об'єкту тестування (В тому  числі міжвіконні переходи, переходи між полями, правильність обробки клавіш  «enter» та «tab», робота з  мишею, функціонування клавіш-акселераторів і  повна відповідність індустріальним стандартам);

    Перевірити об'єкти і їх характеристики  (меню, розміри, положення, стан, фокус наведення і  ін.) у  відповідності ззагальноприйнятим стандартам на  графічний інтерфейс користувача;

Методика:
    Створюється  або доопрацьовуються тести для  кожного з  вікон, на  предмет відповідності навігації і  станів кожного з  об'єктів;

Критерії завершення:
    Кожне вікно протестовано і  задовільняє, базову лінію поведінки, вимогам стандартів і  НЕ  суперечить проектним вимогам;

    Всі виявлені дефекти оброблені і  задокументовані.







Профілювання продуктивності

    Профілювання продуктивності  - оцінка часу відгуку програми  або бази, швидкості транзакцій і  інших, залежних від  часу параметрів. Мета робіт по  профілізації  - переконатися в  тому, що  вимоги по  продуктивності додатка  або бази задоволені.

    При профілюванні продуктивності реєструються функції поведінки продуктивності об'єкта тестування в  залежності від  спеціальних умов  (робоча нагрузка, апаратна конфігурація, тип  операційної системи).

Мета Тестування:
    Перевірити поведінку продуктивності зазначених транзакцій  або бізнес функцій при  очікуваній завантаженні і  очікування завантаження в  найгіршому випадку.

Методика:
    Використовувати тест процедури, розробленої для  функціонального тестування  або тестування бізнес циклів.

    Необхідно постійно модифікувати файли даних, для  збільшення  (ускладнення) кількості транзакцій;

    Необхідно постійно модифікувати скрипти, для  того, щоб збільшити кількість ітерацій, виконання кожної з  транзакцій;

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

Критерії завершення:
    Одиночна транзакція  або одиничний користувач: Успішне завершення тесту без  будь-яких збоїв  протягом очікуваного  або необхідного періоду часу виконання транзакції;

    Всі виявлені дефекти оброблені і  задокументовані.




Тестування навантаження

    Тестування навантаження використовується для  визначення поведінки об'єкта тестування в  змінюючих робочих навантаженнях, для  оцінки здібностей об'єкта правильно функціонувати в  мінливих умовах. Мета навантажувального тестування полягає в  тому, щоб визначити і  гарантувати правильність роботи всіх системних функцій поза  максимального робочого навантаження. В доповненні даний вид  тестування забезпечує оцінку характеристик роботи об'єкта тестування (час  відгуку, час транзакції, а  також будь-яких операцій чутливих по  часу)

Мета Тестування:
    Перевірити продуктивність об'єкта тестування для  позначених операцій при  змінюючих зовнішніх умовах.

Методика:
    Використовувати тести, розроблені для  функціонального тестування  або тестування бізнес-циклів.

    Змінювати склад даних, їх  число і  складність для  збільшення часу відгуку

Критерії завершення:
    Множинні транзакції від  безлічі користувачів виконані без  проблем  (правильно, в  певному часовому інтервалі)

    Всі виявлені дефекти оброблені і  задокументовані.




Стресове тестування

    Стресове тестування - підвид навантажувального тестування, мета якого полягає в  знаходженні помилок, поява яких спровоковано дефіцитом ресурсів (недостатня  кількість вільної оперативної пам'яті  або місця на  диску,  або недостатньої пропускної здатності мережі). Даний вид  тестування дозволить ефективно відловити помилки, що не  виникають при  звичайному, нормальному тестуванні.

    Також даний вид  тестування зручно використовувати для  отримання інформації про  пікові навантаження, після яких тестований додаток перестає працювати  (або працює некоректно)

Мета Тестування:
    Переконатися в  тому, що  цільові тести виконані без  помилок при  наступних умовах проведення тестування:

· вичерпана вільна пам'ять на сервері, або її розмір близький до критичного;

· одночасно до сервера звертається максимально можливе (задане) число клієнтів;

· одночасно безліч користувачів виконують однакові дії з одними і тими ж записами (або різними записами).

Методика:
    Використовувати тести, створені для навантажувального тестування та тестування продуктивності;

    Для ефективного тестування, машина, для  якої проводиться тестування, повинна навмисно мати обмежене число доступних ресурсів

Критерії завершення:
    Всі заплановані тести виконані, системні межі досягнуті і  НЕ  виявлено збоїв в  тестованому додатку;

    Всі виявлені дефекти оброблені і  задокументовані.




Об'ємне тестування

    Мета об'ємного тестування полягає в  знаходженні меж розміру переданих даних. Об'ємне тестування також ідентифікує безперервне максимальне завантаження  або обсяг інформації, яка може бути оброблена в  заданому інтервалі часу  (наприклад, об'єкт тестування обробляє набір записів для  генерації звіту, а  об'ємне тестування дозволить застосувати великі тестові бази даних і  перевірити те, яким чином функціонує програма. Чи призвела вона  правильне повідомлення).

Мета Тестування:
    Перевірити вірність функціонування об'єкта тестування при  наступних сценаріях:

· підключено або змодельоване максимальне число клієнтів;

· бізнес-функції на протязі тривалого часу коректно виконуються;

· максимальний розмір бази досягнутий, а множинні запити і звіти виконані одночасно.

Методика:
    Використовувати тести, створені для навантажувального тестування та тестування продуктивності;

    Імітувати максимальне число клієнтів для  проходження найбільш гіршого сценарію роботи системи;

    Створити максимальну базу і  підтримувати звернення клієнтів до неї впродовж тривалого часу.

Критерії завершення:
    Всі заплановані тести виконані;

    Специфічні системні обмеження досягнуті  або перевищені без  помилок;

    Всі виявлені дефекти оброблені і  задокументовані.




Конфігураційне тестування

    Спеціальний вид  тестування, спрямований на  перевірку сумісності об'єкта тестування з  різним апаратним та  програмним забезпеченням.

    Конфігураційне тестування необхідно для гарантованої сумісності об'єкта тестування з  максимально можливим обладнанням, для  забезпечення надійної роботи. Також КУ  має враховувати тип  операційної системи.

    RUP  має розгалужений механізм по  плануванню і  одночасного запуску конфігураційних тестів на  різних платформах одночасно.

    Тест повинен враховувати такі критерії, як: встановлене програмне забезпечення  (і їх версії), наявність і  версії драйверів обладнання, наявність обладнання  (довільній комбінаціях).

Мета Тестування:
    Перевірити об'єкт тестування на  сумісність з  оголошеним в  специфікації обладнанням, операційними системами та  програмними продуктами третіх фірм.

Методика:
    Використовуються скрипти функціонального тестування;

    До  початку тестування відкрити максимальне число загальновідомих додатків;

    Тестування проводиться на  різних платформах.

Критерії завершення:
    Тестовані програми правильні в  будь-якій аппартно-програмному середовищі.

    Всі виявлені дефекти оброблені і  задокументовані.




Інсталяційне тестування

    Останній вид  тесту в  нашому списку, але  перша функція, з  якої користувач розпочне ознайомлення з  програмним продуктом.

    Даний вид  тестування перевіряє здатність об'єкта тестування коректно і без збоїв встановитися на  комп'ютер користувача  (доустановити, оновитися) з  обробкою всіх можливих виняткових ситуацій  (брак  місця, збій харчування).

Мета Тестування:
    Упевнитися в  тому, що  об'єкт тестування правильно інсталюється на  систему, що задовольняє всім програмно-апаратним вимогам з  інструкції по  інсталяції. Особлива увага приділяється наступним видам установки:

1. нова інсталяція, нова машина, що не інстальований на неї раніше;

2. оновлення існуючої версії (перевстановлення);

3. оновлення зі старої версії (апгрейд)

4. спроба установки старої версії поверх нової.

 

Методика:
    Розробити скрипти для  перевірки всіх перерахованих комбінацій.

Критерії завершення:
    Установка, оновлення та  деінсталяція відбуваються коректно;

    Виняткові ситуації обробляються коректно.

    Всі виявлені дефекти оброблені і  задокументовані.




Введення


    В цій статті я розповім про застосування інструменту спочатку призначеного для функціонального тестування при тестуванні нагрузочної web частини системи електронного документообігу (СЕД).

    Навіщо взагалі це знадобилося? Ми переслідували дві мети - введення автоматичних тестів для наших web-додатків і створення навантажувальних тестів на основі функціональних тестів.

    Чому для тесту використовувався саме Selenium, а не більш підходящий інструмент - LoadRunner, jMeter? За допомогою LoadRunner's навантажувальний тест був проведений, але результати були поставлені під сумніви - при емуляції двохсот користувачів сторінки завантажувалася за 2 секунди плюс-мінус 2%, хоча при відкритті цих же сторінок з браузера відображення відбувалося більш ніж за 3 секунди. Так що хотілося провести навантажувальні тести максимально наближені до реальності, а це можна зробити тільки за допомогою повної емуляції поведінки користувача. Для цього якраз підходили інструменти для функціонального тестування з їх роботою з браузерами - сайт відкривався б через звичайний браузер, тобто так як робив би це користувач.

 


Про Selenium


    Для функціонального тестування був обраний саме Selenium з простої причини - він кращий з безкоштовних інструментів для функціонального тестування. Якщо точніше - у нього хороша підтримка віддаленого управління (Selenium Server, Selenium Grid), багато документації (в тому числі і російською мовою ( habrahabr.ru/post/151715/  habrahabr.ru/post/152653/ ) і підтримка всіх основних браузерів (хоча це вже більше заслуга WebDriver).

 


Загальна архітектура

 

 

    Додаток розділений на рівні (для наочності на схемі елементи кожного рівня мають осмислені назви, а не просто Тест 1, Методи 2).

    Перший рівень - рівень «запускальщика» тестів. Він просто запускає тести. У налаштуваннях конфігурується кількість потоків, кількість запусків тесту, класи тесту.

    Другий рівень - самі тести. Вони виконують бізнес операції - авторизацію, відкривають списки документів, відкривають документи, переходять по вкладках документів.
    Третій рівень - рівень роботи з web-елементами. У ньому міститися атомарні користувальницькі операції по роботі з системою - відкриття списку документів, перехід до певного документу, робота з вкладками документа.

    Для початку перерахованих дій буде достатньо для забезпечення мінімальної роботи з системою. Надалі вони будуть додаватися.

    Поділ на ці рівні дає таку ж вигоду - можна запускати тести як з «запускальщика», так і без - просто запуск одного тесту з середовища розробки. Винесення атомарних користувальницьких операцій на окремий рівень дозволить надалі відмовитися від написання тестів на Java, а розробити свій DSL для того, що б тести могли писати будь-які люди.

 


Запуск тестів


    Програма для запуску jUnit тестів досить проста і складається з трьох класів - клас, який виконує зазначені тести у своєму потоці; клас «слухача» jUnit тесту для підрахунку часу виконання тесту; клас для формування потоків і їх запуску.
Код Runner 'а

Final Int threadCount = readThreadCount ();

Final Int invocationCount = readInvocationCount ();

Final List < Class> testClasses = readTestClasses ();

ExecutorService taskExecutor = Executors.newFixedThreadPool (threadCount);

for ( Int I = 0; i < threadCount; i ++) {

taskExecutor.execute ( New TestRunner (invocationCount, testClasses));

}

taskExecutor.shutdown ();

taskExecutor.awaitTermination (Long.MAX_VALUE, TimeUnit.NANOSECONDS);

 

Код класу запускає тести

 

Public Class TestRunner Implements Runnable {

Public Void Run () {

JUnitCore jUnitRunner = New JUnitCore ();

jUnitRunner.addListener ( New TimeListener ());

for ( Int I = 0; i < invocationCount; i ++) {

for (Class clazz: testClasses) {

jUnitRunner.run (clazz);

}

Thread.sleep (invocationTimeOut);

}

}

}

 

Код listener 'а

 

Public Class TimeListener extends RunListener {

Private EtmPoint Point;

Public Void testStarted (Description description) throws Exception {

point = EtmManager.getEtmMonitor (). createPoint (description.getClassName () + "." + description.getMethodName (); );

}

Public Void testFinished (Description description) throws Exception {

point.collect ();

}

Public Void testFailure (Failure failure) throws Exception {

log.error ( " Error in test." , failure.getException ());

}

}

 



Тести


    Тести були написані прості, але, тим не менш, відображають роботу користувача - відкриття списку документів, відкриття картки документа, перехід по вкладках картки.

    Для написання тестів використовувався jUnit. Хоча також можна використовувати TestNG, який підтримує паралельний запуск тестів (а при навантажувальному тестуванні це обов'язкова вимога). Але обраний був саме jUnit з двох причин: 1) у компанії він широко поширений і давно використовується 2) потрібно було все одно писати свій «запускальщик» який би дозволив, не змінюючи тести, запускати їх в різних потоках (у TestNG паралельний запуск налаштовується в самих тестах) і збирати статистику щодо їх виконання.

    Крім тестів були написані додаткові модулі - pool webdriver'ов (тут слово webdriver використовується в термінології Selenium'а), pool користувачів, pool документів, rule (у термінології jUnit) по зняттю скріншотів при помилку, rule з видачі webdriver тесту, rule авторизації.

    Pool webdriver'ов - це клас, який управляє отриманням webdriver з сервера Selenium'а і розподіляє їх між тестами. Потрібен для того, що б абстрагувати роботу з Selenium'ом - тести будуть отримувати webdriver'и і віддавати їх цьому pool'у. Webdriver'и при цьому не закриваються (не викликається метод close). Це потрібно тому, що б не перезапускати браузер. Тобто таким чином виходить «реіспользованіе» webdriver'ов іншими тестами. Але повторне використання має свої мінуси - при поверненні webdriver'а в pool потрібно «підчистити» за собою - видалити всі cookie або, якщо це зробити не можна, виконати logout.
Так само, як надалі з'ясувалося, цей pool повинен перезапускати webdriveри, сесія яких завершилася. Таке можливо, коли сталася помилка на стороні сервера.

    Pool користувачів потрібний в основному при навантажувальному тестуванні, коли потрібно запускати однакові тести від різних користувачів. Він всього лише по колу віддає логін / пароль чергового користувача.
    Pool документів, так само як і користувачів, потрібний в основному при навантажувальному тестуванні - він по колу повертає id документів певного типу.

    Rule по зняттю скріншотів про помилку, потрібен, як випливає з назви, знімати скріншот про помилку виконання тесту. Він зберігає його в папку і записує в лог назва скриншота зі stacktrace'ом помилки. Дуже допомагає в подальшому «побачити» помилку, а не тільки прочитати її в логах. ( internetka.in.ua/selenium-rule-screenshot/ )
    Rule з видачі webdriver'а тесту потрібен для того, що б автоматизувати отримання перед початком тестового методу і повернення при його закінченні webdriver'а з pool'а webdriver'ів.

    Rule авторизації потрібен так само для автоматизації, тільки тепер авторизація - щоб в кожному тестовому методі не писати login \ logout.

 





Збір статистики


    Для збору статистики було вирішено не винаходити велосипед, а використовувати що-небудь з готових framework'ів. Пошук в інтернеті, на жаль, не дав широкого вибору - всього один інструмент - JETM (http: //jetm.void.fm/), та й він уже не змінювався з 2009 року. Хоча володіє хорошою документацією і невеликий плюси - віддалене підключення по HTTP для перегляду статистики в реальному часі.
    Код конфігурації монітора і запуску http-консолі:

 

BasicEtmConfigurator.configure ();               

EtmMonitor etmMonitor = EtmManager.getEtmMonitor ();

etmMonitor.start ();

HttpConsoleServer server = New HttpConsoleServer (etmMonitor);

server.start ();

 

    Збір статистики походив з двох місць - збирався загальний час виконання тестових методів (з рівня «запускальщика») і час виконання атомарних користувальницьких операцій (з третього рівня). Для вирішення першої проблеми використовувався спадкоємець RunListener'а, в якому перевизначаються методи початку і закінчення тесту і в них збиралася інформація про виконання.

    Рішення другої проблеми можна було виконати «в лоб» - на початку і наприкінці кожного методу, час виконання якого потрібно записувати, писати код для відліку цього часу. Але так як методів вже зараз більше п'яти, а надалі їх буде набагато більше, то хотілося б це автоматизувати. Для цього скористуємось AOP, а конкретно AspectJ. Був написаний простим аспектом, який додавав підрахунок часу виконання всіх public методів з класів з одними операціями. Час підраховувався тільки успішно виконаних методів, що б методи, що вилетіли з помилкою на середині виконання, не псували статистику. Так само виявився один недолік при зборі статистики за назвами методів - так як методи по роботі з одними операціями були універсальні і викликалися усіма тестами, але статистику потрібно було збирати за типами документів. Тому статистика збиралася не тільки за назвою методів, але ще й по їхніх аргументах, що ідентифікують тип документа.

Код методу аспекту

 

Around ( " execution (public static * < Пакет з класами користувальницьких операцій>. *. * (..))" )

Public Object profileMethod (ProceedingJoinPoint thisJoinPoint) throws Throwable {

EtmPoint point = EtmManager.getEtmMonitor (). CreatePoint (getPointName (thisJoinPoint));

Object result = thisJoinPoint.proceed ();

point.collect ();

Return Result;

}

 

Метод getPointName формує назву точки зрізу часу на основі назви методу і його параметрів.

 



Конфігурація Selenium'а


    Сервер Selenium'а підтримує запуск в двох режимах - як standalone сервер (режим запуску за замовчуванням) і як частина загальної мережі з Selenium серверів - Selenium Grid (режими запуску з -role hub та -role node). Так як нам потрібно було використовувати велику кількість комп'ютерів, то перший режим не дуже підходить - в цьому випадку потрібно буде управляти кожним сервером окремо. Тобто, по суті, писати свій менеджер серверів. Хоча, на початку, мені це варіант імпонував - в такому разі у нас буде повний контроль над тим, на якій машині який браузер запускати. Але надалі я від нього відмовився - повний контроль над запуском браузерів виявився не потрібен, плюс Selenium Grid підкупив своєю простотою у використанні. (Посилання на сторінку конфігурації Selenium Grid code.google.com/p/selenium/wiki/Grid2 )

У підсумку прийшли до наступної конфігурації: На одному комп'ютері запускався Selenium в режимі hub з додатковим параметром -timeout 0. Це потрібно було тому, що іноді сесії закривалися по timeout із-за тривалої бездіяльності тестів. На інших комп'ютерах запускався Selenium в режимі node. Для потужних комп'ютерів, здатних забезпечити роботу 15 браузерів, node Selenium'а запускався з додатковим налаштуванням, що дозволяє запускати 15 копій FF і вказує, що одночасно можна працювати з 15 сесіями.

 


Проведення тестів


    Тести проводилися наступним чином - на одному комп'ютері запускався один примірник браузера, який виконував тестові сценарії кілька разів і з якого знімали час виконання. На інших комп'ютерах запускалися ті ж тестові сценарії, але вже на кількох браузерах. Такий поділ для виміру часу потрібно для того, що б одночасна робота браузерів не відображалася на результаті вимірювання. Бо якщо робити ті ж вимірювання на декількох запущених браузерах, то час буде трохи більше.

    Пару слів потрібно сказати про тестові сценарії і підрахунок часу їх виконання. Кожен сценарій включав в себе відкриття документів кожного типу. Тобто спочатку відкривався вхідний документ, потім вихідний документ і т.д. Ось тут потрібно врахувати наступну ситуацію - якщо потрібно зняти час відкриття тільки вхідного документа, і при цьому запустити на всіх машинах виконання тільки по сценарію, то час буде істотно менший (на 50%) ніж, якби знімати час при одночасному виконанні всіх сценаріїв. У моєму випадку, швидше за все це було пов'язано з кешуванням на рівнях web програми та СУБД. І тим, що відкривалося мало унікальних документів. Можливо, при великій кількості різних документів відмінності будуть не настільки істотні.

    В ідеалі хотілося б отримати розподіл користувачів і документів таким, яким воно буде в реально діючій системі. Тобто, наприклад, в реальній системі буде 10 чоловік працювати з вхідними та 30 з вихідними. І в навантажувальні тести так само відобразити це співвідношення - кількість тестів за вихідними в три рази більше ніж з вхідними документами. Але так як ще тестована система поки не ввійшла в експлуатацію та цих даних поки немає, то тестування відбувалося без їх обліку.

 


Підведення підсумків


    В результаті тестів для 1-го, 16-ти, 26-ти і 70 користувачів було складено графік по кожних сценаріях. Поки ще кількість користувачів не занадто велике, що б зробити точні висновки, але вже зараз можна простежити темпи зростання часу.
    Залежність часу відкриття документів від кількості працюючих користувачів:

 

 

Залежність часу списку документів від кількості працюючих користувачів:

 

 

    Далі тести будуть продовжуватися, щоб побудувати графік для 200 користувачів. В результаті повинен вийти графік, схожий на цей (узятий з msdn.microsoft.com/en-us/library/bb924375.aspx ):

 

 

По ньому вже можна буде точно визначити можливості системи і знайти її вузькі місця.



ОРГАНІЗАЦІЯ

На виділеному сервері організовується служба, до завдань якої входять:

· отримання вихідного коду з репозиторію;

· збірка проекту;

· виконання тестів;

· розгортання готового проекту;

· відправка звітів.

РОБОТА З репозитарій

· Всі дані зберігаються в репозиторії;

· Часті коммітов;

· Локальна збірка перед коммітов;

· Предкоммітная збірка на інтегрованому сервері;

· Припинення роботи з репозиторієм до виправлення помилок;

ЗБІРКА ПО РОЗКЛАДОМ

Локальна збірка може здійснюватися:

· за зовнішнім запитом;

· за розкладом;

· за фактом поновлення сховища та за іншими критеріями.

    У разі збірки за розкладом (daily build - щоденна збірка), вони, як правило, проводяться кожної ночі в автоматичному режимі - «нічні збірки» (щоб до початку робочого дня були готові результати тестування). Для відмінності додатково вводиться система нумерації збірок - зазвичай, кожна збірка нумерується натуральним числом, яке збільшується з кожною новою збіркою. Вихідні тексти та інші вихідні дані при взятті їх з репозиторію (сховища) системи контролю версій позначаються номером збірки. Завдяки цьому, точно така ж збірка може бути точно відтворена в майбутньому - достатньо взяти вихідні дані по потрібній мітці і запустити процес знову. Це дає можливість повторно випускати навіть дуже старі версії програми з невеликими виправленнями.

АВТОМАТИЗАЦІЯ ЗБІРКИ

    Для безперервної інтеграції потрібна автоматизація збірки, то є можливість автоматично компілювати програмне забезпечення і з'єднувати його в виконуваний файл. Це потрібно робити швидко, тому що на великі складання може піти багато часу. Без швидкого і надійного процесу складання не буде огляду, необхідного для вирішення виникаючих проблем інтеграції. Коли виконувана інтеграція збірки, вирішуються конфлікти між змінами, внесеними різними розробниками. Коли виявлена проблема, програміст, що працював над вирішенням конфлікту попередньої збірки, може перевірити код за допомогою апаратного моделювання, не затримуючи інших розробників. Однак для досягнення такої ефективності процес інтеграції збірок повинен йти безперервно, так що як тільки закінчується робота над попередньою збіркою, з'являється нова. Це значно відрізняється від щоденного або щотижневого випуску збірок, що практикується іншими процесами.

    Звичайно, для цього потрібна автоматизація процесу складання, тому що непрактично доручати людині задачу багаторазового створення збірок - знову і знову протягом усього робочого дня. Більше того, процес складання повинен виконуватися швидко, для чого часто потрібно багатопоточне складання. При багатопотоковій збірці збірка різних компонентів програмного забезпечення виконується паралельно, що прискорює весь процес. Для цього потрібно більше обладнання і складніший сценарій. А чим складніше сценарій, тим корисніше стають інструменти управління складанням.

УПРАВЛІННЯ РОБОТОЮ

    Основна ідея гнучкої розробки полягає в тому, що робота розбивається на невеликі, керовані фрагменти. Це ж основна передумова CI: виправляти помилки рано і часто. Це запобігає їх переростанню в більші проблеми, які важче вирішити.

    Одна з переваг цього методу - можливість випускати діючі версії меншого розміру, зібрані і протестовані багато разів по ходу проекту. Кожен випуск зменшує ризик для проекту, так як група перевіряє архітектуру, вимоги і оцінює терміни випуску. У гнучких методах ще не завершена робота називається чергою завдань ( backlog ). Коли починають розподіляти роботу малими кроками, так званими спринті, робота, відведена спринту, називається чергою завдань спринту ( sprint backlog ). Робота, що залишилася для майбутніх спринтів, називається чергою завдань проекту. У спринт має включатися стільки роботи, щоб її можна було виконати в терміни, відведені для спринту.

    Цей процес сильно залежить від ряду параметрів, так що група може точно передбачити кількість часу, який знадобиться для вирішення завдання, і, отже, кількість завдань, які можна відвести для одного спринту. Однак збір даних для оцінки цих показників - дуже трудомісткий процес, навіть для невеликої групи. Коли такі невеликі групи об'єднуються, щоб справити більш складний продукт, завдання стає занадто грандіозної, щоб її можна було вирішити вручну.

    На ринку багато інструментів, що допомагають організувати роботу, відслідковувати її завершення і визначити показники, пов'язані з тим, в якому обсязі, як швидко, як добре і т.д. виконана робота. Якщо слідувати методам CI, то до цієї незавершеної роботі потрібно також швидко додавати виявлені помилки інтеграції та переносити її в початок списку високопріоритетних робіт. Кращі продукти цього призначення на ринку забезпечують деякий рівень інтеграції між новими елементами роботи і системою управління збірками, так що помилки, виявлені в кожній збірці, можна швидко виправити і інтегрувати результат з готовими елементами роботи, підвищити його пріоритет і направити потрібної групі.

АВТОМАТИЗОВАНЕ ТЕСТУВАННЯ

    При створенні безлічі збірок група повинна багаторазово тестувати функції, що вже працюють в попередніх збірках. Цей процес повторного тестування, який раніше називали «добротним кодом» (good code), носить ім'я  регресійного тестування . Він гарантує, що внесені зміни не призведуть до помилок в раніше протестованому коді. У разі CI в кінці кожної збірки запускаються автоматичні сценарії регресійних тестів. Це дозволяє розробникам негайно отримувати інформацію про помилки, знайдених в новій збірці. Цей крок попереджає розробників, коли знову створений ними код не відповідає вимогам. Без регресійних тестів розробники знають тільки, що складання виконане. Оскільки тести все одно повинні створюватися, то TDD Не додає додаткову роботу. Просто змінюється порядок дій - спочатку створюються тести, а потім код.

    При традиційній розробці методом «водоспад» проект міг обходитися без всякої автоматизації тестування. Його можна було описувати, виконувати і відчувати нескінченно цілою армією людей. Але як тільки починаються регулярні випуски, цей процес стикається з проблемами. Просто неможливо тестувати систему вручну багато разів на день.

Генерації звітів

Активне оповіщення:

· Mail;

· SMS;

· Миттєві повідомлення.

Пасивне оповіщення:

· Web публікація;

· Файловий сервер.

ПЕРЕВАГИ

· Скорочення ручних операцій - етапи створення, збірки і тестування програмного забезпечення проводяться в автоматичному режимі.

· Наявність робочої ІТ-системи на всьому протязі процесу розробки - у проектної команди завжди є свіжа версія рішення для демонстрації замовнику, отримання зворотного зв'язку і швидкого доопрацювання.

· Якість програмного забезпечення - в рамках Continuous Integration використовуються різні програмні засоби для контролю якості коду, що дозволяє скоротити кількість помилок.

· Мінімізація ризиків - дефекти виявляються на ранніх стадіях розробки інформаційної системи, що допомагає уникнути збільшення термінів і вартості проекту.

· Окупність інвестицій в ІТ - автоматизація процесу розробки забезпечують високу ефективність і надійність інформаційної системи.

1.4 НЕДОЛІКИ

· витрати на підтримку роботи безперервної інтеграції;

· потенційна необхідність у виділеному сервері під потреби безперервної інтеграції;

· негайний ефект від неповного або непрацюючого коду відучує розробників від виконання періодичних резервних включень коду в репозиторій.

· у разі використання системи управління версіями вихідного коду з підтримкою розгалуження, ця проблема може вирішуватися створенням окремої «гілки» (англ. branch) проекту для внесення великих змін (код, розробка якого до працездатного варіанти займе декілька днів, але бажано більш часте резервне копіювання в репозиторій). Після закінчення розробки і індивідуального тестування такої гілки, вона може бути об'єднана (англ. Merge) з основним кодом або «стволом» (англ. Trunk) проекту.

ІНСТРУМЕНТИ

· Розгортання і підготовка до роботи: VMWare, Microsoft Hyper-V, Citrix Xen, Parallels.

· Засоби розробки: Eclipse, MS Visual Studio, Borland Delphi і т. д.

· Системи контролю версій: StarTeam, Perforce, CVS, PVCS, VSS, Synergy, Subversion, GIT і т. д.

· Компілятори і засоби збирання: Compilers, Linkers, Ant, Make, Nant MSBuild, Maven.

· Контроль якості: Mercury Quality Center, LoadRunner, TestDirector, WinRunner, Xunit, Clover, IBM Functional, Performance & Manual Tester

· Сервера інтеграції

1. CruiseControl - сервер інтеграції для Java (див. так само CruiseControl ).

2. ThoughtWorks Cruise - комерційний сервер інтеграції від компанії ThoughtWorks (є безкоштовна версія).

3. CruiseControl.NET - сервер інтеграції для.NET (див. так само CruiseControl.NET )

4. CruiseControl.rb - сервер інтеграції для Ruby.

5. Hudson - open-source сервер інтеграції, створений як альтернатива CruiseControl. Функціональність розширюється плагінами.

6. Bitten - open-source сервер інтеграції написаний на Python, інтегрується з Trac.

CruiseControl.NET


Безперервна інтеграція
    У ході розробки структурно-складних програмних продуктів, в якийсь момент виникає необхідність автоматизувати процеси збирання і інтеграції розроблюваних проектів і дистрибутивів. Безперервна інтеграція - це практика розробки програмного забезпечення, що припускає часту (до декількох разів протягом дня) автоматизовану складання і подальше автоматичне тестування поточної версії продукту. Такий підхід дозволяє знизити трудомісткість самої інтеграції, і виявляти в ній помилки і протиріччя, починаючи з самих ранніх етапів. Зауважимо, що дана методика передбачає використання системи управління версіями (як наприклад CVSNT, Subversion) для зберігання вихідних кодів і всього іншого, що необхідно для побудови та тестування проекту.
Раніше розробляючи статичний аналізатор коду PVS-Studio для пошуку 64-бітних і паралельних помилок, ми вирішували це завдання за допомогою файлів сценаріїв командного рядка Windows. Хоча такий підхід здається найбільш простим і не вимагає

 




Введення

    Почати опис можливостей продукту Rational Purify хочеться перефразуванням одного дуже відомого вислову:  «з  точністю до  мілліБАЙТА ». Дане порівняння не  випадково, адже саме цей продукт спрямований на  вирішення всіх проблем, пов'язаних з  витоками пам'яті. Ні для кого не  секрет, що  багато програмних продуктів поводять себе  «Не  надто скромно », замикаючи на  себе під  час роботи всі  системні ресурси без  великої на то необхідності. Подібна ситуація може виникнути внаслідок небажання програмістів доводити створений код  «до  розуму », але  частіше подібне відбувається не з-за ліні, а  через неуважність. Це зрозуміло - сучасні темпи розробки ПЗ в умовах найжорстокішого пресингу з  боку конкурентів не  дозволяють приділяти занадто багато часу оптимізації коду, адже для  цього необхідні і  висока кваліфікація, і  наявність достатньої кількості ресурсів проектного часу. Як мені бачиться, маючи в  своєму розпорядженні надійний інструмент, який би сам в процесі роботи над  проектом вказував на всі чорні діри в  використанні пам'яті, розробники почали б його повсюдне впровадження, підвищивши надійність створюваного ПЗ. Адже і  тут ні для кого не  секрет, що в більшості складних проектів першочергове завдання, що стоїть перед розробниками полягає в  заміщенні стандартного оператора  «new» в  С ++, так як він НЕ зовсім адекватно себе поводить при  розподілі пам'яті.
    Ось на створенні \ написанні власних велосипедів і  дозволить заощадити Purify.

    Загальні можливості по  управлінню Purify схожі з  Quantify, за  винятком специфіки самого продукту. Тут також можна тестувати багатопотокові програми, також можна робити  «зліпки» пам'яті під  час тестування програми.

    Особливості використання цього додатка стосуються специфікою відловлюючих помилок і  способом видачі інформації.
    Інформація видається в  вигляді списку, з  найменуванням знайденої помилки  або попередження. При розгортанні списку з  конкретною помилкою виводиться додатковий набір даних, що характеризують помилку.



Основні параметри виведення

· Address.  IP адреса модуля, в якому виявлено помилку або попередження;

· Error Location.  Опис модуля з помилкою. В випадку тестування модуля з вихідними текстами, то в даному полі можна переглянути фрагмент коду, який викликав появу помилки;

· Allocate Location.  Різновид «Error Location », показує фрагмент коду, в якому був розподілений блок пам'яті, робота з яким, призвела до помилки

    Робота з Purify можлива як при наявності вихідних текстів і налагоджувальної інформації, так і без неї. В разі відсутності debug-інформації аналіз помилок ведеться тільки по ip-адресах. Так само як і в випадку з Quantify, можливий детальний перегляд функцій з dll-бібліотек. В цьому випадку наявність налагоджувальної інформації не є необхідністю.

Повідомлення про   помилки та   попередження

    Для того, щоб мати уявлення про  можливості продукту, опишемо те, які помилки і  потенційні помилки можуть бути присутніми в  тестованому додатку.

    Відзначимо різницю між помилкою і  потенційної помилкою і  опишемо:

· Помилка - Доконаний факт нестабільної  або некоректної роботи програми, призводить до  неадекватних дій додатка  або системи. Прикладом подібної помилки можна вважати вихід за  межі масиву  або спроба запису даних за 0 адресою;

· Потенційна помилка  - в додатку є фрагмент коду, який при нормальному виконанні не призводить до помилок. Помилка виникає тільки в разі збігу обставин, або не проявляє себе ніколи. До даної категорії можна віднести такі особливості, як ініціалізація масиву з ненульової адреси, скажімо, є масив на 100 байт, але кожен раз звернення до нього виробляється з 10 елемента. В цьому випадку Purify вважає, що є потенційний витік пам'яті розміром в 10 байт.

    Природно, що  подібна поведінка може бути викликана специфікою додатка, наприклад, так  поводитися може текстовий редактор. Тому в  Purify застосується поділ інформації на  помилки і  потенційні помилки  (які  можна сприймати як  специфіку).

    Список помилок і  потенційних помилок досить об'ємний і  постійно поповнюється. Коротко опишемо основні повідомлення, що виводяться після тестування:

· Array Bounds Read  Вихід за межі масиву при читанні;

· Array Bounds Write  Вихід за межі масиву при записі;

· Late Detect Array Bounds Write  Повідомлення вказує, що програма записала значення перед початком або після кінця розподіленого блоку пам'яті;

· Beyond Stack Read  Повідомлення вказує, що функція в програмі збирається читати поза поточного покажчика вершини стека;

· Freeing Freed Memory  Спроба звільнення вільного блоку пам'яті;

· Freeing Invalid Memory  Спроба звільнення некоректного блоку пам'яті;

· Freeing Mismatched Memory  Повідомлення вказує, що програма пробує;

· Free Memory Read  Спроба читання вже звільненого блоку пам'яті;

· Free Memory Write  Спроба запису вже звільненого блоку пам'яті;

· Invalid Handle  Операції над неправильним дескриптором;
Handle In Use Індикація витоку ресурсів. Неправильна індикація дескриптора;

· Invalid Pointer Read \ Write  Помилка при читанні \ записі з недоступного блоку пам'яті;

· Memory Allocation Failure  Помилка в запиті на розподіл пам'яті;

· Memory Leak  Витік пам'яті;

· Potential Memory Leak  Потенційний витік пам'яті;

· Null Pointer Read  Спроба читання з нульової адреси;

· Null Pointer Write  Спроба запису в нульовий адрес;

· Uninitialized Memory Copy  Спроба копіювання непроініціалізірованного блоку;

· UMR: Uninitialized Memory Read  Спроба читання непроініціалізірованного блоку.

    Попередження і помилки зручно групувати за певними ознаками, щоб легше можна було відшукати потрібне попередження і відкинути непотрібні.

    Відзначимо категорії і  приналежність до них різних повідомлень:

· Allocation And   deallocation.  Робота з пам'яттю;

· DLL messages.  Інформаційні повідомлення по зовнішнім бібліотекам;

· Invalid handles.  Неправильний дескриптор;

· Invalid pointers.  Неправильний покажчик;

· Memory leaks.  Витік пам'яті;

· Parameter errors.  Помилка параметра;

· Stack errors.  Помилка при роботі зі стеком;

· Unhandled exception.  Виняток;

· Uninitialized memory.  Використання непроініціалізірованного блоку пам'яті.

    Багато статичних помилок можуть виловлювати компілятори на етапі розробки програмного модуля або програми. На цьому етапі переваги Purify НЕ дуже видно.

    Всі механізми аналізу помилок відкриваються при  виконанні додатка, при  динамічно мінливих умовах.

    Розглянемо більш докладно список відловлювальних помилок, визначивши їх  приналежність до  категорій з  прикладами на  C ++ / C:

    ABR: Array Bounds Read.  Вихід за  межі масиву при  читанні.
    Відома хвороба всіх розробників - неправильно поставлена умова в  циклі. Відповідно, помилка, яка має місце бути в  програмі, пов'язана з  читанням зайвої інформації, може проявити себе, а  може і НЕ проявити. Але вона є потенційною помилкою.

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [5]; // Виділяємо пам'ять під   масив з 5 символів

ptr [0] = 'e';
ptr [1] = 'r';
ptr [2] = 'r';
ptr [3] = 'o';
ptr [4] = 'r';
for (Int  I = 0; i ≤ 5; i ++) {
// Помилка, при   i = 5 - вихід за   межі масиву
cerr < <  «ptr [" < < i  < < " ] ==" < < ptr [i] < < '\ n';
}
delete [] ptr;
return (0);
}

    ABW: Array Bounds Write.  Вихід за  межі масиву при записі.
    Імовірність того, що  додаток може неадекватно поводитися з-за цієї помилки більш висока, так як запис за  адресою, що перевищує розмір блоку, викликає виняток.

    Відзначимо, що  пам'ять можна визначити статично, масовому, як  показано в  прикладі. А можна динамічно  (наприклад, виділивши блок пам'яті по  ходу виконання додатка).

    За замовчуванням, Purify успішно справляється тільки з  динамічним розподілом, чітко виводячи повідомлення про  помилку. В випадку статичного розподілу, все  залежить від розмірів «Купи» і  налаштувань компілятора.

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr  = New  Char [5]; // Виділяємо пам'ять під   масив з   5 символів
for (Int  I = 0; i ≤ 5; i ++) {
// Помилка, при   i = 5   - вихід за   межі масиву
ptr [i] = '! ';
cerr < < " ptr [" < < i  < < " ] ==  «< < ptr [i] < < '\ n';   // ABW + ABR   When I is 5
}
delete [] ptr;
return (0);
}

    BSR: Beyond Stack Read.  Повідомлення вказує, що  функція в  програмі збирається читати поза  поточного покажчика вершини стека

Категорія: Stack Error

#include < windows.h>
#include < iostream.h>
#define A_NUM 100
char * create_block  (void)
{
char block [A_NUM]; // Помилка: масив повинен бути статичним
for (Int  I = 0; i < A_NUM; i ++) {
block [i] = '! ';
}
return (Block); // Помилка: невідомо, що   повертати
}

int main  (int, char **)
{
char * block;
block = create_block  ();
for (Int  I = 0; i < A_NUM; i ++) {
// BSR: немає   гарантії, що   елементи з   «create_block" до сих пір знаходяться в   стеку

cerr < <  «element  # " < < i < < «Is  " < < block [i] < < '\ n';
}
return (0);
}

    FFM: Freeing Freed Memory.  Спроба звільнення вільного блоку пам'яті.

    В великому додатку важко відстежити момент розподілення блоку і  момент звільнення. Дуже часто методи реалізуються різними розробниками, і, відповідно, можлива ситуація, коли розподілений блок пам'яті звільнюєтьсядвічі на  різних ділянках програми.

Категорія: Allocations And   deallocations

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr1 = New  Char;
char * ptr2 = ptr1; // Помилка: повинен дублювати об'єкт, а НЕ копіювати покажчик
* ptr1 = 'a';
* ptr2 = 'b';
cerr < < " ptr1" < <  «is  " < < * ptr1 < < '\ n';
cerr < <  «ptr2" < <  «is  " < < * ptr2 < < '\ n';
delete ptr1;
delete ptr2; // Помилка - звільнення незайнятої пам'яті
return (0);
}

    FIM: Freeing Invalid Memory.  Спроба звільнення некоректного блоку пам'яті.

    Розробники часто плутають прості статичні значення і  покажчики, намагаючись звільнити те, що НЕ звільняється. Компілятор  завжди здатний проаналізувати і  нейтралізувати даний вид  помилки.

Категорія: Allocations And   deallocations

#include < iostream.h>

int main  (int, char **)
{
char a;
delete [] & a; // FIM: в   динамічній пам'яті немає   об'єктів для   знищення
return (0);
}

    FMM: Freeing Mismatched Memory.  Повідомлення вказує, що  програма пробує звільняти пам'ять з  неправильним ВИКЛИКОМ API  для того типу пам'яті.

Категорія: Allocations And   deallocations

#include < windows.h>

int main  (int, char **)
{
HANDLE heap_first, heap_second;
heap_first = HeapCreate  (0, 1000, 0);
heap_second = HeapCreate  (0, 1000, 0);
char * pointer =  (char  *) HeapAlloc  (heap_first, 0, sizeof  (int));
HeapFree  (heap_second, 0, pointer);
// Помилка - в   другий купі НЕ   виділялася пам'ять

HeapDestroy  (heap_first);
HeapDestroy  (heap_second);
return (0);
}

    FMR: Free Memory Read.  Спроба читання вже  звільненого блоку пам'яті

    Все та ж проблема з  покажчиком. Блок розподілений, звільнений, а  потім, в  відповідь на  подію, по  покажчику починають записуватися (Або читатися) дані.

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [2];
ptr [0] = '! ';
ptr [1] = '! ';
delete [] ptr; // Помилка - звільнення виділеної пам'яті
for (Int  I = 0; i < 2; i ++) {
// FMR: помилка - спроба читання звільненій пам'яті
cerr < <  «element  # " < < i < < «Is  " < < ptr [i] < < '\ n';
}
return (0);
}

    FMW: Free Memory Write.  Спроба запису вже  звільненого блоку пам'яті

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * ptr = New  Char [2];
ptr [0] = '! ';
ptr [1] = '! ';
delete [] ptr; // спеціально звільняємо виділену пам'ять
for (Int  I = 0; i < 2; i ++) {
ptr [i] * = 'A';   // FMR + FMW: пам'ять для   * ptr вже   звільнена
cerr < <  «element  # " < < i < < «Is  " < < ptr [i] < < '\ n'; // FMR
}
return (0);
}

    HAN: Invalid Handle.  Операції над  неправильним дескриптором

Категорія: Invalid handles

#include < iostream.h>
#include < windows.h>
#include < malloc.h>
Int  Main  (int, char **)
{
Int  I = 8;
(void) LocalUnlock ( (HLOCAL) i); // HAN: i   - НЕ   є описувачем  об'єкта пам'яті
return (0);
}

    HIU: Handle In   Use.  Індикація витоку ресурсів. Неправильна індикація дескриптора.

#include < iostream.h>
#include < windows.h>
static long GetAlignment  (void)
{
SYSTEM_INFO desc;
GetSystemInfo  (& desc);
return (Desc.dwAllocationGranularity);
}
Int  Main  (int, char **)
{
const long alignment = GetAlignment  ();
HANDLE handleToFile = CreateFile ( «File.txt",
GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL, NULL);
if  (handleToFile  == INVALID_HANDLE_VALUE) {

cerr < <  «Помилка  відкриття, створення файлу \ n ";
return (1);
}
HANDLE handleToMap = CreateFileMapping  (handleToFile, NULL, PAGE_READWRITE, 0, alignment,  «mapping_file" );
if  (handleToMap  == INVALID_HANDLE_VALUE) {
cerr < <  «Unable to create actual mapping \ n ";
return (1);
}
char * ptr = (Char  *) MapViewOfFile  (handleToMap, FILE_MAP_WRITE, 0, 0, alignment);

if  (ptr  == NULL) {
cerr < <  «Unable to Map  Into Address Space \ n ";
return (1);
}
strcpy  (ptr,  «hello \ n" );
// HIU: handleToMap до сих пір доступний і   описує існуючий об'єкт
return (0);
}

    IPR: Invalid Pointer Read.  Помилка звернення до  пам'яті, коли програма намагається зробити читання з  недоступної області.

Категорія: Invalid pointers

#include < iostream.h>

#include < windows.h>
Int  Main  (int, char **)
{
char * pointer =  (char  *) 0xFFFFFFFF;
// Помилка   - покажчик на   зарезервовану область пам'яті

for (Int  I = 0; i < 2; i ++) {
// IPR: звернення до   зарезервованої частини адресного простору
cerr < <  «pointer [" < < i  < < " ] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    IPW: Invalid Pointer Write.  Помилка звернення до  пам'яті, коли програма намагається зробити запис з  недоступної області

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * pointer =  (char  *) 0xFFFFFFFF;
// Помилка   - покажчик на   зарезервовану область пам'яті

for (Int  I = 0; i < 2; i ++) {
// IPW + IPR: звернення до   зарезервованої частини адресного простору
pointer [i] = '! ';
cerr < <  «ptr [  «< < i < < «] ==  «< < ptr [i] < < '\ n';
}
return (0);
}

    MAF: Memory Allocation Failure.  Помилка в  запиті на  розподіл пам'яті. Виникає в  випадках, коли проводиться спроба розподілити занадто великий блок пам'яті, наприклад, коли вичерпано файл підкачки.

Категорія: Allocations And   deallocations

#include < iostream.h>
#include < windows.h>
#define BIG_BLOCK 3000000000   // розмір блоку
Int  Main  (int, char **)
{
char * ptr = New  Char [BIG_BLOCK / sizeof  (char)];
// MAF: занадто великий розмір для   розподілу
if  (ptr  == 0) {
cerr < <  «Failed to allocating, AS  Expected \ n ";
return (1);
} else {
cerr < <  «Got  " < < BIG_BLOCK < <  «bytes  @ " < <  (Unsigned  Long) ptr < < '\ n';
delete [] ptr;
return (0);
}
}

    MLK: Memory Leak.  Витік пам'яті

    Поширений варіант помилки. Багато сучасних програм грішать тим, що НЕ віддають системі розподілені ресурси по  закінченні своєї роботи.

Категорія: Memory leaks

#include < windows.h>
#include < iostream.h>
Int  Main  (int, char **)
{
(Void) New  Int [1000];
(void) New  Int [1000];
// результат втрати пам'яті
return (0);
}

    MPK: Potential Memory Leak.  Потенційний витік пам'яті
    Іноді виникає ситуація, в  якій необхідно провести ініціалізацію масиву не з нульового елемента. Purify вважає це  помилкою. Але розробник, який пише горезвісний текстовий редактор може ініціалізувати блок пам'яті не з нульового елемента.

Категорія: Memory leaks

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
static int  * pointer = New  Int [100000];
pointer + = 100; // MPK: втратили початок масиву
return (0);
}

    NPR: Null Pointer Read.  Спроба читання з  нульової адреси
    Більше  за все програм на  С \ С ++. Дуже часто себе помилка проявляє при  динамічному розподілі пам'яті додатком, так як НЕ всі розробники ставлять умову на  отримання блоку пам'яті, і  виникає ситуація, коли система не  може видати блок зазначеного розміру і  повертає нуль. За через відсутність умови розробник як НЕ в ніж НЕ бувало починає проводити операції над  блоком, адреса в  пам'яті якого 0.

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int
Main  (int, char **)
{
char * pointer =  (char  *) 0x0;   // вказівник на   нульовий адрес
for (Int  I = 0; i < 2; i ++) {
// NPR: спроба читання з  нульового адреси
cerr < <  «pointer [" < < i < < «] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    NPW: Null Pointer Write.  Спроба запису в  нульовий адрес

Категорія: Invalid pointers

#include < iostream.h>
#include < windows.h>
Int
Main  (int, char **)
{
char * pointer =  (char  *) 0x0;   // вказівник на   нульовий адрес
for (Int  I = 0; i < 2; i ++) {
// NPW: помилка доступу
pointer [i] = '! ';
cerr < <  «pointer [  «< < i < < «] ==  «< < pointer [i] < < '\ n';
}
return (0);
}

    UMC: Uninitialized Memory Copy.  Спроба копіювання непроініціалізірованного блоку пам'яті

Категорія: Unitialized memory

#include < iostream.h>
#include < windows.h>
#include < string.h>

int main  (int, char **)
{
int  * pointer = New  Int [10];
Int  Block [10];
for (Int  I = 0; i < 10; i ++)
{
pointer [i] = block [i];   // UMC попередження
cerr < < block [i] < < " \ n";

}

delete [] pointer;
return (0);
}

    UMR: Uninitialized Memory Read.  Спроба читання непроініціалізірованного блоку пам'яті

Категорія: Unitialized memory

#include < iostream.h>
#include < windows.h>
Int  Main  (int, char **)
{
char * pointer = New  Char;
cerr < <  «* pointer is  " < < * pointer < < '\ n';
// UMR: pointer вказує на   непроініціалізірованний елемент
delete [] pointer;
return (0);
}

Робота з   фільтром

    Щоб не  захаращувати користувальницький інтерфейс зайвими даними, в  Purify передбачена система гнучких фільтрів.
    Система фільтрів Purify здатна регламентувати тип  помилок і  попереджень та  помилок  (угруповання  проводиться по  категоріям) до  програми, але і число досліджуваних зовнішніх модулів  (щоб  розробник міг  концентруватися тільки на  помилках власного модуля). Таким чином можливе створення універсальних фільтрів з  осмисленими іменами, які обмежують потік інформації. Число створюваних фільтрів нічим не  обмежена.

    Фільтри створюються і  призначаються і  модифікуються через верхнє меню  (View → CreateFilter і  View → FilterManager). За замовчуванням Purify виводить всі  повідомлення і  попередження.

    Малюнок показує зовнішній вигляд  вікна створення фільтра  (View → CreateFilter). Тут ми  маємо можливість по  вибору повідомлень, які потрібно фільтрувати.

    Пункт General - управляє ім'ям фільтру і  коментарем, його  супроводжуючим, Source - визначає місце розташування вихідних файлів, для  яких необхідно вивести повідомлення. Підхід використовується в тому випадку, коли відбувається виклик одного модуля з  іншого, щоб обмежити кількість інформації в  звіті.
    Наступний малюнок демонструє вид  вікна налаштувань фільтрів. Тут є можливість по  активації \ деактваціі фільтрів і  модулів.

    Вище згадувалося, що  Purify НЕ  обмежує число фільтрів. Слід розуміти, що НЕ обмежується НЕ  тільки загальне число фільтрів, але і їх кількість на  один протестований додаток.

    Обмеження по  модулям, яке також можна виставити в  даному діалозі, визначає число зовнішніх модулів, попередження від  яких з'являються в  звіті.













































































































































































































































API

    Rational Purify  також має ряд  функцій інтерфейсу, впливаючи на  які, розробник на  етапі створення програми може користуватися всіма благами, що надаються даним додатком.
    Опишемо основні функції інтерфейсу з  короткою характеристикою, розділивши попередньо всі  функції по  основних групах:

Функції установки статусу розподілених блоків:

· PurifyMarkAsInitialized.  Встановлює позначку на вказаний блок, роблячи його поміченим, як проініціалізований;

· PurifyMarkAsUninitialized.  Ставить прапор ініціалізації;

Функції тестування станів розподілених блоків

· PurifyAssertIsReadable.  Перевіряє, чи доступний блок пам'яті для читання;

· PurifyAssertIsWritable.  Перевіряє, чи доступний блок пам'яті для запису;

· PurifyIsInitialized.  Перевіряє, проініціалізований блок пам'яті чи ні;

· PurifyIsReadable.  Перевіряє блок пам'яті на можливість читання;

· PurifyIsWritable.  Перевіряє блок пам'яті на можливість запису;

Функції, що визначають руйнування

· PurifySetLateDetectScanCounter.  Визначає лічильник сканування купи. Підраховує кількість операцій. За замовчуванням, Purify сканує пам'ять через кожні 200 операцій з пам'яттю, або кожні 10 секунд;

· PurifySetLateDetectScanInterval.  Визначає інтервал пошуку купи. За замовчуванням - 10 секунд;

· PurifyHeapValidate. Примусово перевіряє пам'ять на наявність помилок;

Функції, що визначають витоку пам'яті

· PurifyAllInuse.  Повертає значення, що визначає кількість використаної пам'яті;

· PurifyClearInuse.  Повертає значення, яке показує кількість пам'яті, розподіленої після останнього дзвінка PurifyClearInuse або PurifyNewInuse;

· PurifyAllLeaks.  Повертає число знайдених витоків у пам'яті. Знаходить як прямі витоки пам'яті, так і непрямі;

· PurifyClearLeaks.  Визначає число звільнених блоків пам'яті за час останнього звернення до PurifyClearLeaks або PurifyAllLeaks;

· PurifyNewLeaks.  Визначає число нових витоків пам'яті за час останнього звернення до PurifyNewLeaks або PurifyClearLeaks.

Збереження даних і   експорт

    Purify  дозволяє зберігати результати тестування  (file → save copy as) в  чотирьох різних уявленнях, що дозволяють найбільш ефективним чином отримати інформацію про  хід тестування.

Розглянемо варіанти збереження:

· Purify Error unfiltered.  Зберігає дані про тестуванні в вигляді «Як є »без фільтрів;

· Purify error filtered.  Зберігає дані про тестування з застосованими фільтрами;

· Text expended.  Зберігає дані в текстовому вигляді про тестування в розширеному поданні (з виведенням знайдених помилок, з коротким описом);

· Text view.  Зберігається тільки згадка про знайдені помилки, без додаткового опису.

    При встановленому MS Outlook, можливо відправлення звіту поштою через пункт file → send з верхнього меню Purify.


Параметри тестування

    Перед виконанням тестованої програми, можливо, задати додаткові налаштування, які зможуть налаштувати Purify на  ефективне тестування.

    Запуск програми проводиться точно також як і в випадку з  Quantify  (по  F5  або file → Run). Параметри налаштування знаходяться пункті Settings, вікна, що з'явилося.

Перша сторінка діалогу представлена ​ ​ на  малюнку

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

· Report AT   Exit.  Дана група дозволяє отримувати більш детальну інформацію про всіх покажчиках і блоках пам'яті, що не приводили до помилок пам'яті. За замовчуванням, Purify виводить звіти тільки по тим блокам, які були розподілені, але НЕ були звільнені. В більшості випадків такий підхід виправданий, так як зазвичай розробника цікавлять саме помилки. Інші пункти активізують по мірі необхідності, коли потрібно мати загальне уявлення про використання пам'яті тестованим додатком;

· Error Suppretion.  Група визначає ступенем детальності виведеної інформації.
За замовчуванням, активований пункт «Show First Message Only ». В цьому випадку по закінченні тестування, Purify виводить скорочений звіт по модулям, тобто, якщо в одному модулі знайдено 10 витоків пам'яті, то інформація про витоки на основному екрані буде описувати тільки ім'я помилки, число блоків і ім'я модуля. Тобто ми отримуємо узагальнену інформацію помилок у блоці. В разі необхідності отримання окремого звіту по кожному окремому блоку, відключаємо даний пункт.

· Call Stack Length.  Визначає глибину стека;

· Red Zone Length.  Управляє числом байтів, яке вбудовується в код тестованої програми при операціях пов'язаних з розподілом пам'яті. Збільшення числа сприяє кращому збору інформації, але істотно гальмує виконання додатка;

    Закладка PowerCheck  дозволить налаштувати рівень аналізу кожного окремо взятого модуля. Існує два способи інструментації тестованої програми: Precise і Minimal. В першому випадку проводиться детальне інструментування коду, але при цьому модуль працює відносно повільно. Під другому випадку, проводиться коротке інструментування, при якому Purify вносить в модуль менше налагоджувальної інформації, і, як наслідок, здатна відловити менше число помилок. Останній підхід виправданий, коли додаток викликає масу зовнішніх бібліотек від третіх фірм, котрі не будуть піддаватися правці.


Поделиться:



Последнее изменение этой страницы: 2019-04-09; Просмотров: 75; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.971 с.)
Главная | Случайная страница | Обратная связь