Dynamic - White box
Розробка тестів методом білої скриньки (white-box test design technique): Процедура розробки або вибору тестових сценаріїв на підставі аналізу внутрішньої структури компонента або системи. (ISTQB)
Засновані на структурі методи проектування тестування використовуються для отримання контрольних прикладів структурної характеристики, наприклад структури вихідного коду або структури меню. Якщо ці методи застосовуються до вихідного коду програми, очікувані результати для контрольних прикладів виходять з базису тестування. Вибір, які з заснованих на структурі методів проектування тестування використовувати у кожному конкретному випадку залежить від природи базису тестування та від властивих ризиків. (ГОСТ 56920)
Потік даних (data flow): Абстрактне уявлення послідовності та можливих змін стану об'єктів даних, у якому стан об'єкта це: створення, використання чи знищення. (Beizer)
Потік керування (control flow): Послідовність подій (шляхів) у процесі виконання компонента чи системи. (ISTQB)
Динамічне тестування методом білого ящика - це стратегія, заснована на внутрішніх шляхах, структурі та реалізації програмного забезпечення, що тестується. Тести тут виконуються динамічно, тобто. із запуском об'єкта тестування та засновані на різних видах покритті коду (шляхів виконання програми).
Глобально основних технік динамічного тестування методом білої скриньки всього дві:
Тестування потоку керування (Control Flow Testing);
Тестування потоку даних (Data Flow Testing).
Фактично, це динамічна частина одного цільного тестування, статична частина якого - аналіз та побудова графа, що описується в попередній темі про статичний аналіз, а на цьому визначається цільове покриття (Coverage Target), створюються відповідні тест-кейси, тести виконуються та результати виконання тестів аналізуються .
Рівні тестового покриття у тестуванні потоку управління
Під "покриттям" мається на увазі відношення обсягу коду, який вже був перевірений, до обсягу, який залишилося перевірити. У тестуванні потоку управління покриття визначається у вигляді декількох різних рівнів. Зауважимо, що ці рівні покриття представлені не по порядку. у деяких випадках простіше визначити вищий рівень покриття, а потім визначити нижчий рівень покриття за умов високого.
100% покриття операторів(Statement/node coverage). Оператор (statement) - це сутність мови програмування, що зазвичай є мінімальним неподільним виконуваним блоком (ISTQB). Покриття операторів - це метод проектування тестів методом білого ящика, який включає виконання всіх виконуваних операторів (if, for і switch) у вихідному коді як мінімум один раз. Відсоткове відношення операторів, що виконуються набором тестів, до їх загальної кількості є метрикою покриття операторів. Борис Бейзер написав: "тестування, менше ніж це (100% покриття операторів), для нового програмного забезпечення є несумлінним і має бути визнано злочином. …". Незважаючи на те, що це може здатися розумною ідеєю, на такому рівні покриття може бути пропущено багато дефектів та ускладнений аналіз покриття деяких керуючих структур.
Невикористані вирази (Unused Statements);
Мертвий код (Dead Code);
Гілки, що не використовуються (Unused Branches);
Відсутні оператори (Missing Statements);
100% покриття альтернатив/гілок (Decision/branch/all-edges/basis path/DC/C2/decision-decision-path/edge coverage). "Рішення" - це програмна точка, в якій control flow має два або більше альтернативних маршруту (гілки). На цьому рівні достатньо такого набору тестів, в якому кожен вузол з розгалуженням (альтернатива), що має TRUE або FALSE на виході, виконується як мінімум один раз, таким чином, для покриття по гілках потрібно як мінімум два тестові приклади. На цьому рівні не враховуються логічні вирази, значення компонентів яких виходять викликом функцій. На відміну від попереднього рівня покриття, цей метод враховує покриття умовних операторів з порожніми гілками. Покриття альтернатив не гарантує покриття всіх шляхів, але гарантує покриття всіх операторів;
Для повнішого аналізу компонент умов у логічних операторах існують такі три методи, які враховують структуру компонент умов і значення, які вони приймають при виконанні тестових прикладів.
100% покриття умов (Condition/Toggle Coverage). Розглядаються лише висловлювання з логічними операндами, наприклад, AND, OR, XOR. На цьому рівні достатньо такого набору тест-кейсів, у якому кожна умова, що має TRUE та FALSE на виході, виконана як мінімум один раз. Покриття умов забезпечує кращу чутливість до control flow, ніж decision coverage. Для забезпечення повного покриття за даним методом кожна компонента логічної умови в результаті виконання тестових прикладів повинна набувати всіх можливих значень, але при цьому не потрібно, щоб сама логічна умова набувала всіх можливих значень, тобто. Condition Coverage не дає гарантії повного decision coverage;
100% покриття умов + альтернатив (Decision + Condition coverage). У цьому рівні тест-кейси створюються кожному за умови і кожної альтернативи, тобто. даний метод поєднує вимоги попередніх двох методів - для забезпечення повного покриття необхідно, щоб як логічна умова, так і кожна його компонента набула всіх можливих значень;
100% покриття множинних умов(Multiple condition coverage). Для виявлення неправильно заданих логічних функцій було запропоновано метод покриття за всіма умовами. При цьому методі покриття повинні бути перевірені всі можливі набори значень компонентів логічних умов: умов, альтернатив та умов/альтернатив. Тобто. у разі n компонент знадобиться 2^n тестових прикладів, кожен із яких перевіряє один набір значень. Тести, необхідні повного покриття даним методом, дають повну таблицю істинності для логічного висловлювання. Незважаючи на очевидну повноту системи тестів, що забезпечує цей рівень покриття, даний метод рідко застосовується на практиці у зв'язку з його складністю та надмірністю. Ще одним недоліком методу є залежність кількості тестових прикладів від структури логічного виразу. Крім того,
Покриття нескінченного числа шляхів . Якщо, у разі зациклювання, кількість шляхів стає нескінченною, то є сенс суттєво їх скоротити, обмеживши кількість циклів виконання, що дозволить зменшити кількість тестових випадків. Перший варіант – не виконувати цикл зовсім; другий – виконати цикл один раз; третій – виконати цикл n разів, де n – це невелике значення, що представляє символічну кількість повторень циклу; четвертий – виконати цикл m разів, де m – максимальна кількість повторень циклу. Крім того, можна виконати цикл m-1 та m+1 разів. Перед тим, як розпочинати тестування потоку керування, має бути обраний відповідний рівень покриття;
100% покриття шляхів (Path Coverage). Перевіряє кожен лінійно незалежний шлях у програмі, що означає, що кількість тестових прикладів буде еквівалентно цикломатичної складності програми. Для коду модулів без циклів кількість шляхів, як правило, досить мала, тому насправді можна збудувати тест-кейси для кожного шляху. Для модулів з циклами кількість шляхів може бути величезною, що становить нерозв'язну проблему тестування.
Шлях насправді є напрямом, потоком виконання, який слідує за послідовністю інструкцій. Він охоплює функцію від входу до точки виходу. Він охоплює statement, branch/decision coverage. Покриття шляху можна зрозуміти в наступних термінах:
Loop coverage : використовується для перевірки того, що всі цикли були виконані та скільки разів вони були виконані. Мета цього методу покриття - переконатися, що цикли відповідають запропонованим умовам і не повторюються нескінченно та не завершуються ненормально. Цикл тестування спрямовано моніторинг від початку остаточно циклу. Цінним аспектом цієї метрики є визначення того, чи виконуються цикли while і for більш ніж один раз, т.к. ця інформація не повідомляється іншими метриками;
Function coverage : показує, чи ви викликали кожну функцію чи процедуру;
Call coverage : показує, чи виконували кожен виклик функції. Гіпотеза полягає в тому, що помилки зазвичай виникають в інтерфейсах між модулями (функція, що викликає, і функція, що викликається). Також відомий як покриття пари дзвінків (call pair coverage);
7 вищезгаданих рівнів описуються у книзі Копленда “A Practitioner's Guide to Software Test Design”, але можна знайти й інші
FSM coverage (Finite State Machine Coverage)
Кінцеві автомати (FSM) мають кінцеве число станів, умов, що призводять до внутрішніх переходів між станами, і відповідне поведінка ПЗ у стані автомата. Автомат зазвичай моделює поведінку логіки, що управляє.
Покриття FSM – покриття кінцевого автомата, безумовно, є найскладнішим методом покриття коду. У цьому методі покриття вам потрібно подивитися, як багато переходів/відвідувань визначених за часом станів (time-specific states). Воно також перевіряє, скільки послідовностей включено в кінцевий автомат. Кінцеві автомати можуть мати безліч гілок і кілька функціональних шляхів, а також будь-який прихований шлях (функціональний шлях, пропущений під час перевірки, або шлях, ненавмисно введений на етапі реалізації), в дизайні може викликати серйозне порушення функціональності, а також може створити глухий кут (система не може самостійно вийти із певного стану, навіть якщо намічений стимул присутній).
Basis Path testing
Мета тестування базового шляху - на відміну від DD Path (Decision-to-decision path) отримати повне покриття тих шляхів, які знаходяться між точками прийняття рішень (decisions points) з високим бізнес-ризиком та високою бізнес-цінністю, т.к. перевіряти всі можливі шляхи коштує занадто дорого. Це гібрид branch testing та path testing
LCSAJ coverage
LCSAJ (LCSAJ): Послідовність лінійного коду з переходами, що складається з трьох елементів (умовно визначається номерами рядків вихідного коду):
початок лінійної послідовності виконуваних операторів
кінець лінійної послідовності
цільовий рядок коду, що отримує керування після кінця лінійної послідовності
(ISTQB)
LCSAJ (linear code sequence and jump) «лінійна послідовність коду та перехід». Кожен LCSAJ є сегментом коду, який виконується послідовно від початкової точки до кінцевої точки, а потім перериває послідовний потік для передачі потоку управління. Кожен рядок коду має щільність (density), тобто кількість разів, коли номер рядка з'являється у LCSAJ.
Один LCSAJ складається з трьох компонентів:
Початок сегмента, який може бути гілкою або початком програми;
Кінець сегмента, який може бути кінцем гілки чи кінцем програми;
Конкретна цільова лінія;
Його основне застосування під час динамічного аналізу програмного забезпечення, щоб допомогти відповісти на запитання «Скільки тестування достатньо?». p align="justify"> Динамічний аналіз програмного забезпечення використовуються для вимірювання якості та ефективності тестових даних програмного забезпечення, де кількісне визначення виконуються в термінах структурних одиниць коду при тестуванні. У вужчому сенсі, LCSAJ є добре визначеним лінійним ділянкою коду програми. При використанні в цьому сенсі LCSAJ також називають JJ-шлях (jump-to-jump path). 100% LCSAJ означає 100% Statement Coverage, 100% Branch Coverage, 100% procedure або Function call Coverage, 100% Multiple condition Coverage (у ISTQB йдеться лише про 100% Decision coverage).
Певні метрики використовують для перевірки покриття коду. Ці показники можуть допомогти нам визначити, чи достатньо тестування чи ні. Ці показники називаються коефіцієнтом ефективності тестування (TER – Test Effectiveness Ratio):
TER-1: кількість операторів, виконаних за допомогою тестових даних, поділена на загальну кількість операторів;
TER-2: кількість гілок потоку керування, виконаних тестовими даними, поділена на загальну кількість гілок потоку керування;
TER-3: кількість LCSAJ, виконаних тестовими даними, поділена на загальну кількість LCSAJ;
Дослідники посилаються на коефіцієнт покриття шляхів завдовжки n LCSAJ як коефіцієнт ефективності тесту (TER) n + 2.
2. Data Flow Testing
Тестування потоку даних - це ще один набір методів/стратегій білої скриньки, який пов'язаний з аналізом потоку управління, але з погляду життєвого циклу змінної. Змінні визначаються, використовуються та знищуються, коли в них більше немає потреби. Аномалії в цьому процесі, такі як використання змінної без її визначення або після її знищення можуть призвести до помилки. Ріпак і Вьюкер, популяризатори даного методу, писали: "Ми впевнені, що, як не можна почуватися впевненим у програмі без виконання кожного її оператора в рамках якогось тестування, так само не слід бути впевненим у програмі без бачення результатів використання значень, отриманих від будь-якого та кожного з обчислень".
Коли потік даних через інформаційну систему представлений графічно, він відомий як діаграма потоку даних (Data Flow Diagram). Вона також використовується для візуалізації обробки даних. Але не потрібно плутати це з графом потоку даних (Data Flow Graph), який використовується у Data Flow Testing. Граф потоку даних нагадує граф потоку управління тим, що показує потік обробки через модуль. Додатково до цього він деталізує визначення, використання та знищення кожної зі змінних модуля. Ми побудуємо ці діаграми і переконаємося, що шаблони визначення-використання-знищення є відповідними. Спершу ми проведемо статичний аналіз. Під "статичним" ми маємо на увазі, що ми досліджуємо діаграму (формально через перевірки чи неформально швидкими переглядами). Потім ми проведемо динамічні випробування модуля. Під "
Так як тестування потоку даних засноване на потоці управління модуля, то, ймовірно, потік управління в основному правильний. Процес тестування потоку даних зводиться до вибору достатньої кількості тестів, таких як:
кожне " визначення " простежується кожному за його " використання " ;
кожне "використання" простежується з відповідного йому "визначення";
Щоб це зробити, перерахуємо маршрути в модулі. Порядок виконання такий самий, як і у випадку з тестуванням потоку управління: починаємо з точки входу в модуль, будуємо лівий маршрут через весь модуль і закінчуємо на виході з нього. Повертаємося на початок і йдемо по іншому напрямку у першому розгалуженні. Прокладаємо цей шлях остаточно. Повертаємося на початок і йдемо по іншому напрямку у другому розгалуженні, потім у третьому тощо, поки не пройдемо всі можливі шляхи. Потім створимо хоча б один тест для кожної змінної, щоб покрити кожну пару визначення-використання.
Існують умовні позначення, які можуть допомогти в описі послідовних у часі пар у життєвому циклі змінної:
~ - змінна ще не існує або попередній етап був останнім
d – визначено, створено, ініціалізовано
k - не визначено, вбито
u - використовується (c - використання обчислень; p - використання предикатів)
Таким чином, ~d, du, kd, ud, uk, uu, k~, u~ є цілком допустимими комбінаціями, коли ~u, ~k, dd, dk, kk, ku, d~ є аномаліями, потенційними або явними помилками . В даний час практично всі вони ефективно виявляються компіляторами або принаймні IDE і нам рідко потрібно виконувати статичний аналіз для виявлення цих аномалій. Те саме стосується і динамічного аналізу, який сфокусований на дослідженні / виконанні du пар - сучасні мови програмування знижують ймовірність виникнення проблем, пов'язаних з du. Так що в даний час така перевірка в основному не варта зусиль.
Джерела:
Лі Копланд - “A Practitioner's Guide to Software Test Design”, Глави 10 і 11
Дод. матеріал:
Last updated