Автоматизація процесів тестування програмного забезпечення

 















ДИПЛОМНА РОБОТА

за ОКР магістра

Тема: Автоматизація процесів тестування програмного забезпечення


РЕФЕРАТ


Дипломна робота: 63 с., 19 рис.,1 табл., 16 джерел, 1 додаток.

Об'єктом дослідження є процес тестування програмного забезпечення.

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

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

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

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

Перелік ключових слів: ТЕСТУВАННЯ, ГЕНЕРАЦІЯ ТЕСТОВОГО НАБОРУ, СКІНЧЕНИЙ АВТОМАТ, ДІАГРАМА СТАНІВ ТА ПЕРЕХОДІВ.

ABSTRACT

master project of Anna Skumina, the 5th course student (Oles Honchar Dnipropetrovsk National University, Faculty of Applied Mathematics, Computer technologies department) is devoted to the research of algorithm for automation of test cases generation for manual execution. The existing formal models for software requirements specification have been considered and the finite state machine has been finally chosen. developed approach provides the variety of advantages such as guaranteed achievement of transition coverage, reducing ability to make a mistake via fixation of maximum value of steps in the test, selection of tests, which provide additional coverage, to the set. The extra effect is the detection of software requirements faults and contradictions during their translation into the state transition graph.the end, the application has been built to demonstrate declared approach, which can be easily used in a separate way or be integrated into the larger system of software testing support.

Bibliography 16, pictures 19, supplement 1.


ЗМІСТ


ВСТУП6

ПОСТАНОВКА ЗАДАЧІ11

РОЗДІЛ 1. АНАЛІЗ ПРОБЛЕМ ПРОЦЕСУ ТЕСТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ12

1.1 Зв'язок між тестування і забезпеченням якості17

1.2 Аналіз процесу тестування програмного забезпечення18

1.3 Автоматизація процесу тестування програмного забезпечення20

1.4 Аналіз переваг автоматичного тестування28

1.5 Аналіз недоліків автоматичного тестування29

1.6 Обґрунтування генерації тестів як більш ефективного підходу30

1.7 Аналіз процесу ручного створення функціональних тестів32

РОЗДІЛ 2. ОБГРУНТУВАННЯ ПІДХОДУ38

2.1 Формальна модель представлення вимог38

2.2 Скінчений автомат43

2.3 Діаграма станів і переходів47

2.4 Повнота тестового покриття48

2.5 Побудова тестів49

2.6 Побудова тестового набору52

РОЗДІЛ 3. ГЕНЕРАТОР ТЕСТОВОГО НАБОРУ57

3.1 Логіка додатку57

3.2 Вибір середовища57

3.3 Бібліотеки Boost58

3.4 Структура додатку: Класи60

3.5 Структура додатку: Методи62

3.6 Інтерфейс додатку та параметри запуску63

РОЗДІЛ 4. РЕЗУЛЬТАТИ РОБОТИ65

4.1 Приклад №1: Побудова тестів для системи «Банкомат»65

4.2 Приклад №2: Побудова тестового набору для баг-трекінгової системи, представленої графом із циклами69

4.3 Приклад №3: Побудова різних тестових наборів із встановленим рівнем покриття70

ВИСНОВКИ71

СПИСОК ВИКОРИСТАНОЇ ЛІТЕРАТУРИ74

Додаток А76


ВСТУП


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

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

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

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

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

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

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

У тестування є і інший аспект. За результатами досліджень Market Enablers - міжнародної мережі компаній, що займається консалтингом та оглядом статистики, грошовий обіг прикладок для смартфонів за 2010 рік склав 2 млрд. доларів, за прогнозами через пять років, у 2015 році, грошовий обіг лише ринку мобільних іграшок буде становити 11 млрд. доларів. І якщо раніше ігри встановлювались з дистрибутивів, наперед придбаних, або годинами завантажувались із Інтернету, то сьогодні у епоху сенсорних екранів та швидкісного Інтернету користувач очікує встановлення програми за одним дотиком. Якщо ні - він за миті може завантажити прикладку конкурента. Зросли також користувацькі очікування й щодо зручності програмного інтерфейсу. Інтерфейс повинен бути зручним, ергономічним, привітним, простим та зрозумілим. Ці аспекти сьогодні підлягають тестуванню настільки ж ретельному як і правильність функціонування, адже якість додатку визначається задоволенням користувацьких очікувань.

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

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

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

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

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

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

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

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

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

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

У третьому розділі розглядається структура додатку, що демонструє заявлений підхід.

У четвертому розділі наведено результати експерименту.


ПОСТАНОВКА ЗАДАЧІ


1.Розглянути існуючі формальні моделі для представлення програмного забезпечення.

2.Розробити підхід генерації тестів на основі обраної моделі.

.Розробити програмне забезпечення, що демонструє заявлений підхід - генерує тести і формує з них тестовий набір.

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

РОЗДІЛ 1. АНАЛІЗ ПРОБЛЕМ ПРОЦЕСУ ТЕСТУВАННЯ ПРОГРАМНОГО ЗАБЕЗПЕЧЕННЯ


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

Тому зараз тестування є неодмінною умовою успішного функціонування як для гігантів індустрії таких як Google, Microsoft, IBM чи Oracle, так і для розробників програмного забезпечення "під замовлення".

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

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

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

Каскадна модель або «водоспад»

Найраніша модель розробки ПЗ, запропонована 1970 році Уінстоном Ройсом. Вона передбачає послідовне виконання всіх етапів проекту в чітко фіксованому порядку рис.1.1. Перехід на наступний етап означає повне завершення робіт на попередньому. Вимоги, визначені на стадії формування вимог, суворо документуються у вигляді технічного завдання і фіксуються на весь час розробки проекту. Кожна стадія завершується випуском повного комплекту документації, достатньої для того, щоб розробка могла бути продовжена іншою командою розробників.


Рис. 1.1 Каскадна модель або «водоспад»


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

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

Рис. 1.2 Ціна виправлення дефекту на різних етапах розробки ПО


V- модель


Рис. 1.3 V- модель

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

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

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

Ітеративна модель

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

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


Рис. 1.4 Ітеративна модель

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

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

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

Гнучка розробка

Гнучка розробка бере за основу ітеративний підхід, але зумовлює більш «легкий» та більш орієнтований на людські ресурси механізм. Гнучкі процеси використовують зворотній зв'язок замість планування як основний механізм контролю. Зворотній зв'язок гарантується частими тестами і раннім релізом продукту, що є в розробці. Найпопулярнішими варіаціями гнучких моделей є Екстремальне програмування(XP) і Scrum.

Тестування у гнучкій розробці

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

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

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

1.1 Зв'язок між тестування і забезпеченням якості


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

Тестування - інформаційний сервіс. Тестування вимірює якість, однак не гарантує її.

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

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

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

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

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


1.2 Аналіз процесу тестування програмного забезпечення


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

Фундаментальний процес тестування складається із наступних головних активностей:

·Планування і контроль

·Аналіз і дизайн

·Розробка та виконання тестів

·Оцінка вихідного критерію та звітність

·Активності по завершенню тестування

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

Планування і контроль

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

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

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

Аналіз і дизайн

На етапі аналізу та дизайну загальні цілі транслюються у конкретні умови для тестування і тестові випадки.

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

Розробка та виконання тестів

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

Серед задач даної фази виділяють наступні:

·Розробка і пріорітезація тестових випадків

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

·Створення тестових наборів для ефективного виконання тестів (після умова попереднього тесту є передумовою наступного)

·Перевірка, що тестове обладнання налаштовано правильно

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

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

·Порівняння актуального результату із запланованим

·Звітування відхилень як інцидентів і їх аналіз з метою виявлення їх причин

·Повтор активностей з тестування з метою перевірки, що виправлені дефекти справді виправлені і не стали причиною виникнення нових недоліків.

Оцінка вихідного критерію та звітність

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

Для даного етапу характерні наступні задачі:

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

·Оцінка на предмет необхідності проведення додаткових перевірок о перегляд встановленого вихідного критерію

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

Активності по завершенню тестування

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

Наступні задачі мають місце:

·Перевірка які з запланованих результатів отримані

·Закриття репортів про інциденти

·Документування результатів приймального тестування

·Архівація тестового обладнання для наступного повторного використання

·Використання отриманої інформації для удосконалення процесу


1.3 Автоматизація процесу тестування програмного забезпечення


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

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

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

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

·Інструменти, що асистують управлінню тестуванням і тестами

·Інструменти, що асистують статичному тестуванню

·Інструменти, що асистують створенню тестів

·Інструменти, що асистують виконанню тестів та запису результатів

·Інструменти, що асистують моніторинг продуктивності

Інструменти, що асистують управлінню тестуванням і тестами

Засоби управління застосовуються у всіх процесах тестування протягом всього життєвого циклу розробки ПЗ.

Інструменти управління тестуванням

·Інструменти цієї групи забезпечують:

·Підтримку керування виконанням тестів і процесами тестування

·Інтерфейс для засобів виконання тестів, засобів відстеження дефектів і засобів управління вимогами

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

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

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

Засоби керування вимогами

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

Засоби управління інцидентами

Засоби управління інцидентами зберігають і управляють звітами про відмови, тобто дефекти, збої або проблеми і відхилення, і забезпечують управління звітами про інциденти таким чином, що:

·Допомагають виставляти пріоритети

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

·Визначення статусів (наприклад, скасований, готовий бути протестований або відкладений до наступного випуску).

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

Засоби управління конфігураціями

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

·Зберігають інформацію про версії та збірки ПЗ і проведене тестуванням

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

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

Інструменти, що асистують статичному тестуванню

Засоби підтримки процесу експертизи

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

Засоби статичного аналізу

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

Дотримання стандартів програмування

·Аналіз структури і залежностей (наприклад, посилання на веб-сторінках)

·Допомога в розумінні коду

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

Засоби моделювання

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

Інструменти, що асистують створенню тестів

Засоби проектування тестів

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

Засоби підготовки тестових даних

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

Засоби підтримки виконання і протоколювання тестів

Засоби виконання тестів

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

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

Засоби виконання тестів також можуть використовуватися механізм запису/відтворення тестів. Запис тестових вхідних даних під час дослідницького тестування може бути корисно для відтворення або документування тесту, наприклад, якщо відбулася відмова.

Тестовий вузол / засоби оболонки модульних тестів

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

Тестові порівняльники

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

Засоби вимірювання покриття

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

Засоби безпеки

Засоби безпеки перевіряють на комп'ютерні віруси та DoS-атаки. Інші інструменти безпеки навантажують систему, шукаючи певні уразливості в ній.

Інструменти, що асистують моніторинг продуктивності

Засоби динамічного аналізу

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

Засоби тестування продуктивності / навантажувального / стресового тестування

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

Засоби моніторингу

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

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

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

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

Автоматизація продуктів з графічним користувацьким інтерфейсом розвивалася протягом 4 поколінь інструментів та технік:

Інструменти запису і відтворення (capture/playback tools) записують дії тестувальника під час ручного виконання тестів. Вони дозволяють виконувати тести без прямої участі людини протягом тривалого часу, значно збільшуючи продуктивність і усуваючи необхідність повторення одноманітних дій під час ручного тестування. У той же час, будь-яке незначна зміна інтерфейсу вимагає перезапису тестів. Тому це перше покоління інструментів не ефективне і не масштабується.

Сценарії (Scripting) - форма програмування на мовах, спеціально розроблених для автоматизації тестування ПЗ - пом'якшує багато проблем capture / playback інструментів. Але розробкою займаються програмісти високого рівня, які працюють окремо від тестувальників, безпосередньо запускають тести. До того ж скрипти найбільше підходять для тестування GUI і не можуть бути впровадженими, пакетними або взагалі яким-небудь чином об'єднані в систему. Нарешті, зміни в ПЗ вимагають складних змін у скриптах, і підтримка все зростаючою бібліотеки тестуючих скриптів стає врешті-решт непереборної завданням.

Data-driven testing - методологія, яка використовується в автоматизації тестування. Особливістю є те, що тестові скрипти виконуються та верифікуються на основі даних, які зберігаються в центральному сховищі даних або БД. Роль БД можуть виконувати ODBC-ресурси, csv або xls файли і т.д. Data-driven testing - це об'єднання декількох взаємодіючих тестових скриптів і їх джерел даних у фреймворк, який використовується в методології. У цьому фреймворку змінні використовуються як для вхідних значень, так і для вихідних перевірочних значень: у тестовому скрипті зазвичай закодовані навігація по додатком, читання джерел даних, ведення логів тестування. Таким чином, логіка, яка буде виконана в скрипті, також залежить від даних.


1.4 Аналіз переваг автоматичного тестування


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

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

Швидке виконання - автоматизованому скрипту не потрібно звірятися з інструкціями та документацією, це сильно скорочує затрати часу на виконання.

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

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

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

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


1.5 Аналіз недоліків автоматичного тестування


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

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

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

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

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

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

Автоматичні скрипти для тестувань програм із графічним інтерфейсом користувача є досить чутливим до його змін. Тобто вони можуть бути написані для практично завершеного додатку. І є чуттєвими до будь-яких його змін.

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

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

До того ж, написання автоматичних тестів потребує часу приблизно рівному трьом циклам ручного тестування [l], що робить економічно невигідним створення тестів для нетривалих проектів.

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


1.6 Обґрунтування генерації тестів як більш ефективного підходу


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

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

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

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

Підхід повинен відповідати наступним вимогам:

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

Простота і легкість. Реалізація повинна бути досить простою, щоб не виникло необхідності тривалої і коштовної перепідготовки персоналу.

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


1.7 Аналіз процесу ручного створення функціональних тестів


Розглянемо процес створення тестів і обєднання їх у тестовий набір в ручний спосіб, щоб отримати розуміння задачі для автоматизації.

В найзагальнішому наближені процес створення тестового набору відбувається за наступним алгоритмом:

.Визначення області перевірки

2.Аналіз функціональних вимог до цільової системи

.Визначення вимог до повноти тестового покриття

.Розробка тестів

.Формування тестових наборів

Визначення області перевірки. На цьому етапі визначається функціональність системи, що повинна бути перевірена. Перед кожною задачею тестування ставиться певна ціль в залежності від якої визначається область тестування. До області, що може підлягати перевірці, може відноситись як уся цільова система, так і її окремі компоненти, функції та або якісні характеристики (надійність, практичність, ефективність та інші [3])

Визначення масштабу тестування є необхідним, щоб визначити, що буде перевірятися, а що - ні.

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

У сучасній програмній інженерії функціональні вимоги до програмного забезпечення існують у різних формах в залежності від моделі розробки продукту, зрілості процесу в компанії і ризиків, що несе продукт. Їх форма може набувати як форми документу, строго відповідного стандартизованому шаблону - IEEE 830 [2], так і форми користувацьких історії, занотованих на картках формату 3 на 4, що практикується у гнучких моделях розробки, або просто не задокументованих знань учасників проектної команди - експертів, аналітиків та проектувальників.

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

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

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

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

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

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

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

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

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

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

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

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

Тестовий набор, побудований на основі технік тест дизайну, досягає покриття 60-75% операторів коду і 40-60% операторів вибору (операторів циклу, умовних операторів тощо), у той самий час як тестовий набір, побудований без залучення певних технік досягає покриття 30% операторів коду і лише 20% умовних операторів[4]

Аналіз граничних значень

Мета техніки аналізу граничних значення зосередити зусилля на потенційних помилках, що допущені на границях умов (наприклад, розробник міг вказати >, коли необхідна вимога > або =).

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


Рис. 1.5 Техніка аналізу граничних значень


Тестовий набір, побудований за даною технікою, для діапазонів зображених на рис. 1.5, повинен включати тести на перевірку значень 0,1,99,100.

Розбиття на еквівалентні класи

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

·зменшення тестових випадків у наборі

·для вибору правильних тестів, що покривають усі можливі сценарії

Один тест значення взяв з кожного класу під час тестування.


Рис. 1.6 Техніка розбиття на еквівалентні класи

Тестовий набір для вимог на рис. 1.6, побудований за цією технікою повинен містити тести на перевірку значень -1 (лівий діапазон некоректних даних); 25 (діапазон коректних даних); 105 (правий діапазон некоректних даних).

Зазвичай техніки аналізу граничних значень і розбиття на еквівалентні класи використовуються у комбінації.

Діаграма станів і переходів

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

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

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

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

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

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

Остання під задача - формування тестового набору.

Таким чином загальна задача дослідження - автоматична генерація функціональних тестів для додатків з графічним інтерфейсом для ручного виконання може бути декомпозована на наступні під задачі:

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

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

Побудова тестів на основі моделі. Вибір техніки для побудови тестів на основі формальної моделі.

Формування тестового набору. Розробка алгоритму формування тестового набору.

РОЗДІЛ 2. ОБГРУНТУВАННЯ ПІДХОДУ


2.1 Формальні модель представлення вимог


Формальне представлення функціональних вимог перетворює їх на «машино читаємі», тобто створює передумови повністю автоматизувати процес генерації тестів на їх основі.

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

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

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

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

Приклади логічних числень такі:

Обчислення висловлювань. У ньому є атомарні висловлювання, які можливо залежать від об'єктних змінних, а також логічні зв'язки («і», сполучення), («або», диз'юнкція), («не», заперечення), => («отже», імплікація), = (еквівалентність), за допомогою яких можна з одних висловлювань будувати інші, більш складні.

Обчислення предикатів додає перелік висловлювань можливість використовувати квантори по об'єктним змінним для побудови нових тверджень. Квантори в цьому обчисленні бувають двох видів - «загальності» та «існування». У численні предикатів крім об'єктних змінних є функціональні і предикатні. Перші являють собою різноманітні функції, результат застосування функції до об'єкта - об'єкт. Другі невизначені твердження, результатом їх застосування до об'єкту має бути або «true», або «false» . У не типізованому обчисленні всі об'єкти рівноправні, функції та предикати можуть приймати будь-які об'єкти в якості аргументів. У типізованих численнях кожен об'єкт має тип, а функціональні і предикатні змінні - сигнатуру, тобто список типів параметрів і тип результату для функцій. Відповідно, будувати формули можна лише дотримуючись відповідності типів параметрів типам виразів, які підставляють на місце цих параметрів.

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

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

Приклади алгебраїчних моделей:

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

Алгебраїчні моделі абстрактних типів даних.

Алгебри процесів. Це алгебраїчні обчислення, об'єктами яких є події та процеси, що створюють події або реагують на них. Зазвичай для процесів визначені операції послідовної (';') і паралельної ('||') композиції і операція вибору з двох альтернатив (альтернативна композиція, '+'). Послідовна композиція процесів моделює виконання спочатку першого з них, потім другого. Паралельна композиція моделює паралельне виконання обох процесів. Вибір з двох процесів моделює виконання або першого, або другого. У більшості таких числень процеси можуть взаємодіяти, обмінюючись подіями (один процес породжує подію, інший або інші його споживають). Найбільш широко відомі обчислення процесів CSP (Communicating Sequential Processes), CCS (Calculus of Communicating Systems).

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

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

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

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

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

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

Гібридні автомати застосовувані для моделювання систем, що взаємодіють з безперервними фізичними процесами. У цих автоматах частина змінних зазвичай має значення, зміна яких описується системою диференціальних рівнянь

Широке використання операційних моделей повязано з їх наступними перевагами:

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

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

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

Логіки Хоара є специфічним видом логік, затвердження яких складаються з формул логіки деякого виду та програмних команд. У найпростішому вигляді це трійки {Q} S {R}, де S - частина програми на певній мові, а Q і R - формули обчислення висловлювань, що залежать від змінних, що входять до S. Q інтерпретується як умова, виконання перед початком виконання S (передумова), а R - як умову, що має виконуватись після виконання R (післяумови). Якщо R дійсно завжди істинне після виконання S у стані, де істинно Q, така трійка теж вважається дійсною і має назву «трійка Хоара». У логіці Хоара для деякої мови програмування, семантика цієї мови задається у вигляді правил виведення, які дозволяють з тавтологій виводити крок за кроком істинні трійки Хоара.

Узагальненням логік Хоара є динамічні чи програмні логіки. Вони є спеціальним типом модальних логік, в яких оператори модальності пов'язані з інструкціями програм. Зазвичай використовуються оператори [S] і <S>, де S - деяка програма. Твердження [S]Q означає, що завжди після виконання програми S формула Q істинна, а <S> Q - що після виконання S, Q може виявитися істинною. Трійка Хоара {Q} S {R} може бути представлена ??у динамічній логіці як Q=>[S]R.

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

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

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


2.2 Скінчений автомат


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

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

Два типи автоматів:

Автомат Мілі - скінчений автомат, вихідна послідовність якого залежить від стану автомата і вхідних сигналів.

Автомат Мура - скінчений автомат, для якого функція виходів визначає значення вихіденого символу лише за одним аргуметом - станом автомату.

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

·Аналітичний

·Табличний

·Графічний

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

Аналітично скінчений автомат визначається наступною сукупністю параметрів:


(2.1)


де:- скінчена множина станів автомату;

- елемент множини S, початковий стан автомата,;

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

- відображення типу , функція переходів.

- відображення типу , функція висновків.

Для автомату Мілі наступні рівняння, формули (2.2) - (2.3), характеризують залежність між множинами S, I, O та абстрактним часом :

(2.2)

(2.3)


Особливістю автомату Мілі є те, що функція висновків приймає два аргументи.

Для автомату Мура функція переходу залежить від одного параметру:


(2.4)


Табличний спосіб. Наступні дві таблиці використовуються для задання скінченого автомату Мілі - матриця переходів і матриця висносків.


...Рис. 2.1 Таблиця переходів автомату Мілі


...Рис. 2.2 Таблиця виходів автомату Мілі


Для завдання автомату Мура у табличний спосіб достатньо однієї таблиці.


...Рис. 2.3 Сумісна таблиця автомату Мура

де - вихідний сигнал, що відповідає стану , розташований над ним.


Графічний спосіб передбачає завдання скінченого графу у вигляді орієнтованого графу.

1.Множина S представлена вершинами графу.

2.Функція задана дугами графу, при чому вершини та зєднані дугою, якщо існує перехід із стану в стан .

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

.Функція задана позначками дуг або вершин: для автомату Мілі дуга з вершини у вершину позначається вихідним сигналом , якщо перехід зі стану в стан існує і при цьому має місце вихідний сигнал ; для автомату Мура вихідним сигналом познається вершина, що визначається як


Рис. 2.3 Представлення автоматів Мілі і Мура у вигляді орієнтованого графу


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

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


2.3 Діаграма станів і переходів


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

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

Діаграма станів і переходів являє собою орієнтований граф формула (2.5).


(2.5)


Який задано неперетинаючимися множинами: множиною вершин V і множиною дуг E і двома функціями інцендентності і , що визначають для кожної дуги її початкову та кінцеву вершини. Граф є скінченим, якщо множини V і E.

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

Функції і р визначають відношення суміжності дуг - формула (2.6).


(2.6)


Маршрутом Р називається послідовність суміжних дуг графу така, що при .

Граф будемо називати детермінованим, якщо всі виходящі з нього дуги нееквівалентні.

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


2.4 Повнота тестового покриття


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

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

Більш сильним критерієм є вимога, щоб принаймні одне випробування охоплювати кожну послідовність з N переходів, . Такий підхід називається «N-1 покриттям переходів», тобто якщо тестовий набір покриває усі переходи довжиною одна транзакція, то це «0-е покриття переходів» або просто покриття переходів.

У такому випадку найслабше покриття (всіх станів і переходів) - «0-е покриття переходів»; усіх пар транзакцій - «1-е покриття переходів»; послідовностей з трьох переходів - «2 покриття переходів».

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


2.5 Побудова тестів


Задача побудови тестового набору розпадається на дві підзадачі: побудова усіх маршрутів(тестів) на графі і формування тестового набору.

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


(2.7)


Де F - множина кінцевих вершин.

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

(2.8)


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

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

procedure ПОБУДОВА_МАРШРУТУ(: вершина, accumulator: накопичувач вершин маршруту); begin

if v - фінальна вершина графу, додати її до accumulatorі, зберегти шлях у колекцію, return.

if не існує вихідних ребер з вершини v - return.

if v відвідана більше двох разів - returnдодаємо вершину до accumulator, збільшуємо лічильник відвідування вершини на 1.

while Існують не пройдені ребра графу з вихідною вершиною v

Отримати кінцеву вершину v1 дуги, що зєднана ребром з вершиною v

ПОБУДОВА_МАРШРУТУ ( v1, accumulator)

end

Видаляємо вершину з accumulator. Зменшуємо на одиницю кількість відвідувань даної вершини у шлуху.

end.


Рис. 2.4 Блок-схема алгоритму побудови всіх маршрутів на графі

2.6 Побудова тестового набору


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


(2.9)


де T- множина усіх тестів (шляхів графу),- результуючий тестовий набір,

- покриття графу G, що досягається набором шляхів R,

- покриття графу G, що досягається набором шляхів T.

такого що є розвязком задачі оптимізації

Тестовий набір будується з використанням жадібного алгоритму.

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

У записі алгоритму використовуються наступні умовні позначення:

| S | - потужність множини S

- довжина тесту t, яка вимірюється у кількості тестових впливів

{} - Порожня множина

<> - Порожній упорядкований список

Фіксуємо обмеження довжини тестів M, яке є параметром даного алгоритму. Вважаємо множина непокритих тестових ситуацій C: = повний набір доступних транзакцій, безліч доступних тестів T: = повний набір раніше побудованих тестів, а тестовий набір R :=<>.

Для кожного тесту t з T обчислюємо Cov (t): = безліч тестових ситуацій з C, що покриваються ім. Якщо Cov (t )={}, то видаляємо t з T.

procedure ПОБУДОВА_ТЕСТОВОГО НАБОРУ(M: максимальна довжина кроків тесту, P: вага допустимого перевищення максимальної довжини на користь покриття ); begin

оглушаємо кращим

for кожного тесту з множини тестів Т

if , а , то тест кращий

if і , однак то тест кращий

if , то тест кращий

if , то тест кращий

if , і , а то тест кращий. Додаємо знайдений кращий тест у набір R. Видаляємо із безлічі непокритих ситуації С всі елементи множини .

end

end;

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


&& (2.10)


Друге правило - формула (2.11) вибирає тести з максимально можливим (в межах обмеження довжини) тестовим покриттям - у більшості випадків ця евристика дозволяє зменшити сумарну довжину тестів в наборі за рахунок зменшення їх кількості.


&& && (2.11)


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

if && (2.12)

if && (2.13)


Згідно з пятим правилом - формула (2.14) з двох тестів, що перевищують максимальну довжину, один краще іншого, якщо збільшення довжини компенсується (з урахуванням вагового параметра P) збільшенням покриття.


&& && (2.14)


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

Для настройки алгоритму використовуються параметри M і P.: задає максимальну довжину тестів набору, що генерується, перевищення якої допускається тільки для покриття недосяжних іншими способами тестових ситуацій. Допустимі значення: ціле позитивне число або + ?.: задає вагу перевищення максимальної довжини тестів по відношенню до підвищення покриття. При великих значеннях параметра алгоритм в першу чергу вибирає з тестів, що перевищують максимальну довжину і додають хоча б якесь тестове покриття, самі короткі, що дозволяє зменшити максимальну довжину тестів, але може приводити до істотного збільшення сумарної складності тестового набору; при малих значеннях алгоритм в першу чергу вибирає тести, що покривають більшу кількість тестових ситуацій, що дозволяє мінімізувати сумарну складність тестового набору за рахунок додавання в нього дуже довгих тестів. Допустимі значення: невід'ємні числа (можна нецілі).

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

Рис. 2.5 Блок-схема алгоритму побудови всіх маршрутів на графі

РОЗДІЛ 3. ГЕНЕРАТОР ТЕСТОВОГО НАБОРУ


3.1 Логіка додатку


Додаток повинен реалізувати наступну функціональність для користувача:

Користувач будує діаграму станів і переходів для продукту, що необхідно перевірити.

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

Система будує усі шляхи графа (множину тестових випадків).

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

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


3.2 Вибір середовища


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

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

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

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

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

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

Розширення. Можливість імітації розширення мови для підтримки парадигм, які не підтримуються компіляторами безпосередньо. Наприклад, бібліотека Boost.Bind дозволяє пов'язувати аргументи функцій.

Кроссплатформенность. Стандарт мови накладає мінімальні вимоги на ЕОМ для запуску скомпільованих програм.

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


3.3 Бібліотеки Boost

є зібранням бібліотек, що розширюють С++. Вільно розповсюджуються за ліцензією Boost Software License разом із вихідним кодом.

У даній роботі використовується версія 1.41, на сьогоднішній день найостаннішою версією є 1.46.1 (12.03.2011). Наступні бібліотеки було задіяно:

Бібліотека Boost.Graph надає доступ до структури графу, але приховує деталі його реалізації. Бібліотека пропонує два класи для представлення графу: adjacency_list та adjacency_matrix, і накопичувач для списку ребер edge_list.

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

Adjacency_matrix класу зберігає ребра матриці (де | V | є числом вершин). Елементи цієї матриці представляють ребер у графі. Матриця суміжності подання особливо добре підходить для дуже щільних графіків, тобто ті, де число ребер .

Edge_list клас адаптер, який приймає будь-які ітератор ребер і реалізує список ребер графу.

Бібліотека містить макрос BOOST_FOREACH, який перебирає (ітерує) послідовність. Послідовністю може виступати STL контейнер, масив, пара літераторів(std::pair of iterators)._CAST

Бібліотека, що визначає функцію lexical_cast.

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


3.4 Структура додатку: Класи


Клас graph_coverage

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


Рис. 3.1 Діаграма класу graph_coverage


#include <graph_coverage.h>

Реалізовані наступні методи класу:

graph_coverage<Graph>(const Graph & graph)

Конструктор класу, створює обєкт - абстракцію покриття графу і ініціалізує значення покриття кожного ребра графу graph як FALSE (непокрите).

aditional_coverage_for_path(std::list<size_t> path) const

Функція повертає додатне число типу size_t, якщо шлях pathпокриває хоча б одне досі непокрите ребро, і 0 - у протилежному випадку.

fully_covered() const

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

add_coverage_for_path(const std::list<size_t>& path)

Функція помічає всі вершини, що зустрічаються у шляху path як покриті.

Клас edge_id

Обєкт класу edge_id містить унікальне описання ребра графу, яким слугують його початого і цільова вершини.


Рис. 3.2 Діаграма класу edge_id


#include "edge.h"

edge_id(size_t vertex_source, size_t vertex_target)

Конструктор класу, ініціалізує m_vertex_source та m_vertex_target значеннями переданих параметрів.

Клас Graph

Клас є синонімом класу boost::adjacency_list і використовується для представлення модельного графу.

#include <boost/graph/adjacency_list.hpp>

Наступні методи із тих, що пропонує клас boost::adjacency_list було використано під час реалізації додатку:

out_edges(vertex_descriptor u, const adjacency_list& g)

Повертає пару літераторів, що ітерує діапазон ребер, що виходять вершини u графу G.

target(edge_descriptor e, const adjacency_list& g)

Функція повертає значення типу vertex_descriptor, що є значенням кінцевої вершини ребра e графу g.

num_vertices(const adjacency_list& g)

Функція повертає кількість вершин графу g.

vertex(vertices_size_type n, const adjacency_list& g)

Функція повертає n-у вершину графу g.

3.5 Структура додатку: Методи


Основні функцій, що використовують при розвязанні задачі:

read_values_in_set<T>(std::istream & input, size_t values_count, std::set<T>* result)

Функція, що читає із вхідного потоку input, values_count кількість ребер, що представлені парами вершин і зберігає їх у контейнер result.

output_test(const std::list<size_t>& path_accumulator, std::ostream & output)

Функція, що виводить у вихідний потік output шлях на графі(тест), що міститься у path_accumulator.

save_to_collection(const std::list<size_t>& path, std::list<std::list<size_t>>& pathes_collection)

Функція поміщає шлях path, у лист pathes_collection - фінальний набір тестів.

trace_graph<BoostAdjacencyList, VertexDescriptor>(const BoostAdjacencyList & graph, const VertexDescriptor & current_vertex, const std::set<size_t>& final_vertices, std::list<size_t>& path_accumulator, std::vector<int>& visits_count_vector, std::list<std::list<size_t>>& pathes_collection)

Функція, що реалізує алгоритм побудови всіх маршрутів на графі із заданим обмеженням (відвідування однієї вершини не більше двох разів). Результат поміщається у pathes_collection. Функція рекурсивна.

Параметрами виступають модельний граф graph, поточна вершина current_vertex, множина кінцевих вершин графу final_vertices, контейнер для шляху, що будується path_accumulator, visits_count_vector - вектор, в якому міститься інформація про кількість відвідування поточної вершини, pathes_collection - тестовий набір, контейнер, в який буде поміщено path_accumulator, коли буде досягнуто одну з вершин множини final_vertices.

read_case(Graph & states_graph, std::set<size_t>& final_states)

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

generate_all_tests(const Graph & states_graph, const std::set<size_t>& final_states, std::list<std::list<size_t>>& tests_collection)

Функція, яка через виклик функції trace_graph(), будує усі шляхи на графі.

choose_best_tests(const size_t M, const double P, const Graph& states_graph, const size_t states_count, std::list<std::list<size_t> >& tests_collection, std::list<std::list<size_t> >& best_tests)

Функція, що реалізує алгоритм побудови тестового набору. Вхідні параметри: M - максимальна довжина переходів у тесті, P - вага допустимого перевищення довжини тесту на користь покриття, states_graph - модельний граф, states_count - кількість станів модельного графу states_graph, tests_collection - повний набір тестів, що побудовано у результаті роботи функції generate_all_tests(),best_tests - контейнер, що містить результуючу тестову послідовність.


3.6 Інтерфейс додатку та параметри запуску


Додаток має консольний інтерфейс.

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

Для коректної роботи додатку він повинен бути запущений з наступними параметрами:


Рис. 3.3 Параметри запуску генератору тестів


РОЗДІЛ 4. РЕЗУЛЬТАТИ РОБОТИ


4.1 Приклад №1: Побудова тестів для системи «Банкомат»


Для демонстрації роботи розробленого методу продемонструємо роботу побудованого додатку для генерації тестів для системи «Банкомат».

Нехай наступні вимоги для процесу автентифікації задані на природній мові у вигляді користувацького сценарію:

Основна діюча особа: Клієнт.

Короткий опис: Перед виконанням будь-якої дії клієнт повинен бути автентифікований.

Передумова: картка вставлена у відповідний отвір банкомату

Основний сценарій:

1.Система запитує пароль.

2.Клієнт вводить пароль.

.Якщо пароль правильний, то карта прийнята

.Якщо пароль не правильний, то

4.1 Якщо кількість введень неправильного паролю менше 3, то

4.1.1 Видати попередження про неправильне пароль.

Інакше:

.2 Видати повідомлення про блокування картки.

.2.1Заблокувати карту.

Післяумова: Немає.

Для використання додатку необхідно транслювати вимоги на природній мові у діаграму станів і переходів кінцевого автомату.

Рис. 4.1 Специфікація «Автентифікації» у вигляді діаграми станів і переходів


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


Рис. 4.2 Діаграма станів і переходів з пронумерованими станами


Запуск генератору тестів:

Рис. 4.3 Запуск Graph.exe


Вміст input.txt:

Рис. 4.4 Файл-описання графу станів і переходів


Побудована послідовність:

{0 -> 1 -> 2 -> 3 -> 4-> 5}

{0 -> 1 -> 2 -> 3 -> 4-> 6}

{0 -> 1 -> 2 -> 3 -> 6}

{0 -> 1 -> 2 -> 6}


Співставляючи унікальні ідентифікатори ребер з їх семантичним значенням отримаємо наступний тестовий набір для ручної перевірки модулю «Автентифікація» системи банкомат:


Таблиця 4.1 Тестовий набір

Тест №11Вставити картку2Перша спроба введення паролю3Друга спроба введення паролю4Третя спроба введення паролюРезультатКартка заблокованаТест №21Вставити картку2Перша спроба введення паролю3Друга спроба введення паролю4Третя спроба введення паролюРезультатКартка прийнятаТест №31Вставити картку2Перша спроба введення паролю3Друга спроба введення паролюРезультатКартка прийнятаТест №41Вставити картку2Перша спроба введення паролюРезультатКартка прийнята

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


4.2 Приклад №2: Побудова тестового набору для баг-трекінгової системи, представленої графом із циклами


Нехай необхідно перевірити зміну станів звіту про дефект у баг-трекінговій системі представленій на рис. 4.5.


Рис. 4.5 Зміна станів звіту про дефект у баг-трекінговій системі


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


{0 -> 1 -> 2 -> 3 -> 4}

{0 -> 7 -> 0 -> 1 -> 6 -> 5 -> 2 -> 3 -> 4}

{0 -> 1 -> 7 -> 0 -> 1 -> 2 -> 3 -> 4}

{0 -> 1 -> 2 -> 3 -> 5 -> 2 -> 3 -> 4}


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

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


4.3 Приклад №3: Побудова різних тестових наборів із встановленим рівнем покриття


Запустимо додаток повторно, для того самого графу станів і переходів з тими самими параметрами алгоритму М і Р.


{0 -> 7 -> 0 -> 1 -> 2 -> 3 -> 4}

{0 -> 1 -> 6 -> 5 -> 2 -> 3 -> 5 -> 2 -> 3 -> 4}

{0 -> 1 -> 7 -> 0 -> 1 -> 2 -> 3 -> 4}


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

Подібна евристика з урахуванням предметної області забезпечує розроблений підхід генерації тестів додатковою перевагою: вирішення проблеми «парадоксу пестициду»[8], описаний ще 1983 році, який полягає в тому, що перевірки, проведені за тією самою послідовністю кроків, не можуть викрити нові дефекти у програмі.


ВИСНОВКИ


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

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

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

2.Залучення автоматизації до виконання і генерації тестів. Недоліки і переваги обох підходів та обґрунтування вибору автоматизації створення тестів як задачі дослідження.

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

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

.Розробка і обґрунтування алгоритмів побудови тестів і тестового набору з використанням рекурсивного і жадібного алгоритмів.

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

Заявлений підхід налічує наступні переваги:

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

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

·Недетермінованість. Евристичний алгоритм відбору тестів до тестового набору може обирати різні тести із встановленою метрикою тестового покриття, таким чином мінімізуючи ризик настання «парадоксу пестициду».

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

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

·Статичне тестування вимог. Під час перетворення представлення вимог на природній мові у скінчено-автоматну модель відбувається їх статичне тестування: виявляються їх недоліки, неточності і протиріччя.

Серед недоліків можна виділити наступні:

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

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

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

СПИСОК ВИКОРИСТАНОЇ ЛІТЕРАТУРИ


1.Cost Benefits Analysis of Test Automation, Douglas Hoffman, Software Quality Methods, LLC; Douglas Hoffman, 1999. - 14 с.

2.IEEE 830.1998 IEEE Recommended Practice for Software Requirements Specifications. Approved 25 June 1998. IEEE-SA Standards Board.

.ISO/IEC 9126 Software engineering

.FOUNDATIONS OF SOFTWARE TESTING ISTQB CERTIFICATION. Dorothy Graham, Erik van Veenendaal, Isabel Evans, Rex Black.

.Certified Tester Foundation Level Syllabus. Version 2010. P.: International Software Testing Qualification Board

.Boost C++ libraries. Режим доступу: #"justify">.МЕТОДИЧНІ РЕКОМЕНДАЦІЇ щодо виконання та оформлення дипломних робіт магістра, спеціаліста, бакалавра та курсових робіт студентами ФПМ ДНУ ім. Олеся Гончара; Кісельова О.М., Варех Н.В., Бойко Л.Т., Сорокін В.І., Зайцева Т.А., Сірик С.Ф., Сегеда Н.Є., Хижа О.Л., 2011. - 33 с.

.Software testing techniques, Boris Beizer, 1983. - 290 p.

.Coding Standards for AutoIt Good Code, A.Skumina, 2011. Режим доступу: #"justify">.Testing of Applications that Work with Databases, A.Skumina, 2010. Режим доступу: #"justify">.Берж К. Теория графов и ее приложения. М.: ИЛ, 1962 - 320c.

.Белов В. В., Воробьев Е. М., Шаталов В. Е. Теория графов. - М.:

Высш. школа, 1976. - 392 c.

.Кристофидес Н.Теория графов. Алгоритмический подход. М.: Мир,

2008 - 429 c.

.Харари Ф. Теория графов. - М.: Мир, 1973- 296 с.

15.В. В. Кулямин, Тестирование на основе моделей, 1999 - 16 c.

.Ayaz Farooq, Reiner R. Dumke, Evaluation Approaches in

Software Testing, University of Magdeburg, 2008 - 79 p.


ДОДАТОК А


Проект реалізованого додатку має наступну структуру:



Edge.h

#ifndef EDGE_H_

#define EDGE_H_

#include <boost/operators.hpp>edge_id : boost::totally_ordered<edge_id>

{:_id(size_t vertex_source, size_t vertex_target)_vertex_source(vertex_source)

m_vertex_target(vertex_target)

{}operator == (const edge_id& rhs) const

{((rhs.m_vertex_source == this->m_vertex_source) && (rhs.m_vertex_target == this->m_vertex_target));

}operator < (const edge_id& rhs) const

{(

(rhs.m_vertex_source < this->m_vertex_source) ||

((rhs.m_vertex_source == this->m_vertex_source) && (rhs.m_vertex_target < this->m_vertex_target))

);

}:_t m_vertex_source;

size_t m_vertex_target;

};

#endif // EDGE_H_

graph_coverage.h

#ifndef GRAPH_COVERAGE_H_

#define GRAPH_COVERAGE_H_

#include "edge.h"

#include <list>

#include <utility>

#include <boost/graph/adjacency_list.hpp>

#include <boost/graph/graph_utility.hpp>

///////////////////////////////////////////////////////////////////////////////////////////////////graph_coverage

{:<typename Graph>graph_coverage(const Graph& graph );_t aditional_coverage_for_path(std::list<size_t> path) const;fully_covered() const;add_coverage_for_path(const std::list<size_t>& path);:std::map<edge_id, bool> coverage_map;_map m_covered_edges;

};

///////////////////////////////////////////////////////////////////////////////////////////////////<typename Graph>_coverage::graph_coverage(const Graph& graph )

{std::pair<Graph::edge_iterator, Graph::edge_iterator> edges_range = boost::edges(graph);(edges_range.first != edges_range.second)

{_t source_vertex = boost::source(*edges_range.first, graph);_t target_vertex = boost::target(*edges_range.first, graph);_covered_edges[ edge_id(source_vertex, target_vertex) ] = false;

++edges_range.first;

}

}

#endif //GRAPH_COVERAGE_H_

graph_coverage.cpp

#include "stdafx.h"

#include "graph_coverage.h"utils

{

/*--------------------------------------------------------------------------------------------*/edges_list_from_path(const std::list<size_t>& path, std::list<edge_id>* out)

{(path.empty());::list<size_t>::const_iterator path_it = path.begin();::list<size_t>::const_iterator path_end = path.end();_t current_vertex = *path_it;

++path_it;(path_it != path_end)

{_t next_vertex = *path_it;>push_back( edge_id(current_vertex, next_vertex) );_vertex = next_vertex;

++path_it;

}

}

/*--------------------------------------------------------------------------------------------*/

}

/////////////////////////////////////////////////////////////////////////////////////////////////////_t graph_coverage::aditional_coverage_for_path(std::list<size_t> path) const

{::list<edge_id> edges_of_path;::edges_list_from_path(path, &edges_of_path);_t coverage = 0;_FOREACH(const edge_id& edge_of_path, edges_of_path)

{_map::const_iterator it = m_covered_edges.find(edge_of_path);(it != m_covered_edges.end());(! it->second)

{// edge not covered yet

++coverage;

}

}coverage;

}

/*-------------------------------------------------------------------------------------------------*/graph_coverage::fully_covered() const

{result = true;_FOREACH(const coverage_map::value_type& edge_coverage, m_covered_edges)

{// Cover all edges in graph= result && edge_coverage.second;

}result;

}

/*-------------------------------------------------------------------------------------------------*/graph_coverage::add_coverage_for_path(const std::list<size_t>& path)

{::list<edge_id> edges_of_path;::edges_list_from_path(path, &edges_of_path);_FOREACH(const edge_id& edge_of_path, edges_of_path)

{// Cover all edges from path_covered_edges[edge_of_path] = true;

}

}

/*-------------------------------------------------------------------------------------------------*/

main.cpp

#include "stdafx.h"

#include "edge.h"

#include "graph_coverage.h"std

{<typename T>::istream& operator >> (std::istream& in, std::pair<T, T>& p )

{>> p.first >> p.second;in;

}

}boost::adjacency_list

< ::listS, ::vecS, ::directedS

> ;

/////////////////////////////////////////////////////////////////////////<typename T>read_values_in_set(std::istream& input, size_t values_count, std::set<T>* result)

{std::istream_iterator<T> in_it(input);std::istream_iterator<T> in_end;(size_t i = 0; i < values_count; ++i)

{(in_it != in_end);std::pair<std::set<T>::iterator, bool> insert_result = result->insert(*in_it);(insert_result.second);(i < values_count - 1)

{

++in_it;

}

}

}

/*------------------------------------------------------------------------*/output_test(const std::list<size_t>& path_accumulator, std::ostream& output)

{<< "{";::list<size_t>::const_iterator end = path_accumulator.end();(std::list<size_t>::const_iterator it = path_accumulator.begin(); it != end;)

{size_t val = *it;

++it;<< val;(it != end)

{<< " -> ";

}

}<< "}" << std::endl;

}

/*------------------------------------------------------------------------*/save_to_collection(const std::list<size_t>& path, std::list<std::list<size_t> >& pathes_collection)

{_collection.push_back(path);

}

/*------------------------------------------------------------------------*/<BoostAdjacencyList, VertexDescriptor

>trace_graph(const BoostAdjacencyList& graph,VertexDescriptor& current_vertex,std::set<size_t>& final_vertices,::list<size_t>& path_accumulator,::vector<int>& visits_count_vector,::list<std::list<size_t> >& pathes_collection)

{size_t vertex_index = current_vertex;

if(final_vertices.find(vertex_index) != final_vertices.end())

{// Reached final vertex_accumulator.push_back(vertex_index);_to_collection(path_accumulator, pathes_collection);_accumulator.pop_back();;

}(out_degree(current_vertex, graph) == 0)

{// No out edges;

}(visits_count_vector[vertex_index] <= 2);( visits_count_vector[vertex_index] == 2 )

{;

}

++visits_count_vector[vertex_index];_accumulator.push_back(vertex_index);std::pair<BoostAdjacencyList::out_edge_iterator, BoostAdjacencyList::out_edge_iterator> out_edges_range = boost::out_edges(current_vertex, graph);(out_edges_range.first != out_edges_range.second)

{next_vertex = boost::target(*out_edges_range.first, graph);_graph(graph, next_vertex, final_vertices, path_accumulator, visits_count_vector, pathes_collection);

++out_edges_range.first;

}_accumulator.pop_back();

-visits_count_vector[vertex_index];(visits_count_vector[vertex_index] >= 0);

}

/*------------------------------------------------------------------------*/read_case(Graph& states_graph, std::set<size_t>& final_states)

{_t vertices_count = 0;::cin >> vertices_count;(vertices_count > 0);_t final_vertices_count = 0;::cin >> final_vertices_count;(final_vertices_count > 0);(vertices_count > final_vertices_count);_values_in_set(std::cin, final_vertices_count, &final_states);::istream_iterator<std::pair<size_t, size_t> > cin_edge_it(std::cin);::istream_iterator<std::pair<size_t, size_t> > cin_edge_end;graph(cin_edge_it, cin_edge_end, vertices_count);::swap(states_graph, graph);

} алгоритм тестування програмне забезпечення

/*------------------------------------------------------------------------*/generate_all_tests(const Graph& states_graph, const std::set<size_t>& final_states, std::list<std::list<size_t> >& tests_collection)

{::list<size_t> path_accumulator;::vector<int> visits_count_vector(boost::num_vertices(states_graph), 0);_graph(states_graph, boost::vertex(0, states_graph), final_states, path_accumulator, visits_count_vector, tests_collection);

}

/*------------------------------------------------------------------------*/choose_best_tests(const size_t M, const double P, // <- algorithm parametersGraph& states_graph,size_t states_count, ::list<std::list<size_t> >& tests_collection,::list<std::list<size_t> >& best_tests)

{_coverage test_coverage(states_graph);

{::list<std::list<size_t> >::iterator tests_it = tests_collection.begin();::list<std::list<size_t> >::iterator tests_end = tests_collection.end();std::list<size_t>* best_test_ptr = &(tests_collection.front()); _t best_test_length = best_test_ptr->size();_t best_test_coverage = test_coverage.aditional_coverage_for_path(*best_test_ptr);_FOREACH(const std::list<size_t>& current_test, tests_collection)

{size_t current_test_coverage = test_coverage.aditional_coverage_for_path(current_test);size_t current_test_length = current_test.size();((current_test_length > M) && (best_test_length <= M))

{;

}( ((current_test_length <= M) && (best_test_length <= M))

&& (best_test_coverage > current_test_coverage) )

{;

}( (best_test_coverage >= current_test_coverage)

&& (best_test_length < current_test_length) )

{;

}( (best_test_coverage > current_test_coverage)

&& (best_test_length <= current_test_length) )

{;

}( double(best_test_length - current_test_length)*P

< double(best_test_coverage - current_test_coverage) )

{;

}_test_ptr = &current_test;_test_length = current_test_length;_test_coverage = current_test_coverage;

}_tests.push_back(*best_test_ptr);_coverage.add_coverage_for_path(*best_test_ptr);

}(!test_coverage.fully_covered() && !tests_collection.empty());

}

/*------------------------------------------------------------------------*/

/////////////////////////////////////////////////////////////////////////

/*Формат воода:

<Количество вершин>

<Количество конечных вершин> <Конечная вершина> [<Конечная вершина> ... ]

<Входная вершина ребра 1> <Выходная вершина ребра 1>

<Входная вершина ребра 2> <Выходная вершина ребра 2>

...

<Входная вершина ребра n> <Выходная вершина ребра n>

*/main(const int argc, const char* argv[])

{_t M = 0;P = 0;(argc != 3)

{::cout << "Usage : " << argv[0] << " <desired test length M> <length-to-coverage coefficient P>" << std::endl;0;

}

{= boost::lexical_cast<size_t>(argv[1]);= boost::lexical_cast<double>(argv[2]);

}states_graph;::set<size_t> final_states;_case(states_graph, final_states);::list<std::list<size_t> > tests_collection;_all_tests(states_graph, final_states, tests_collection);::list<std::list<size_t> > best_tests;_best_tests(M, P, states_graph, boost::num_vertices(states_graph), tests_collection, best_tests);::cout << "Best tests:" << std::endl;_FOREACH( const std::list<size_t>& test, best_tests)

{_test(test, std::cout);

}0;

}

/*------------------------------------------------------------------------*/


ДИПЛОМНА РОБОТА за ОКР магістра Тема: Автоматизація процесів тестування програмного забезпечення

Больше работ по теме:

КОНТАКТНЫЙ EMAIL: [email protected]

Скачать реферат © 2017 | Пользовательское соглашение

Скачать      Реферат

ПРОФЕССИОНАЛЬНАЯ ПОМОЩЬ СТУДЕНТАМ