Path Testing

Path Testing (тестування шляхів) — це метод структурного тестування (white-box testing), при якому тестувальник аналізує всі можливі логічні шляхи через програму з метою створення тестів, що забезпечують максимальне покриття коду. Він базується на аналізі графа потоку управління (Control Flow Graph, CFG) програми.

Основні терміни

1. Граф потоку управління (Control Flow Graph, CFG)

  • Представляє структуру виконання програми у вигляді графа.
  • Вузли (nodes) — окремі інструкції, блоки або умовні оператори.
  • Ребра (edges) — можливі переходи між вузлами, залежно від умов або порядку виконання.

2. Шлях (Path)

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

3. Типи шляхів:

  • Простий шлях (Simple Path): шлях, у якому вузли не повторюються.
  • Циклічний шлях (Cyclic Path): шлях, що містить цикл (наприклад, while або for).
  • Лінійно незалежний шлях: шлях, що містить хоча б одну нову гілку, якої немає в інших шляхах.
  • Базисний шлях (Basis Path): мінімальний набір незалежних шляхів, що дозволяє досягти повного покриття гілок.

Мета Path Testing

  • Перевірити всі можливі варіанти проходження програми.
  • Виявити:
    • логічні помилки,
    • пропущені гілки або умови,
    • мертвий код,
    • небажані петлі (infinite loops),
    • некоректну обробку умов.

Алгоритм проведення Path Testing

  1. Побудова графа потоку управління (CFG) для цільового фрагменту коду.
  2. Ідентифікація всіх можливих логічних шляхів у графі.
  3. Вибір набору незалежних шляхів (як правило, базисних шляхів).
  4. Створення тестових випадків, які дозволяють пройти ці шляхи.
  5. Виконання тестів і аналіз результатів.

Приклад

def max_of_three(a, b, c):
    if a > b:
        if a > c:
            return a
        else:
            return c
    else:
        if b > c:
            return b
        else:
            return c

Граф потоку управління:

          [Start]
        |
     a > b?
     /    \
   T/      \F
 [a > c?] [b > c?]
   / \      / \
 T/   \F  T/   \F
[a] [c] [b]   [c]

Можливі шляхи:

  1. a > b і a > c → return a
  2. a > b і a <= c → return c
  3. a <= b і b > c → return b
  4. a <= b і b <= c → return c

Для повного покриття шляхів потрібно 4 тест-кейси:

  • max_of_three(5, 2, 1) → шлях 1
  • max_of_three(5, 2, 9) → шлях 2
  • max_of_three(2, 5, 1) → шлях 3
  • max_of_three(2, 5, 9) → шлях 4

Переваги Path Testing

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

Недоліки

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

Path Testing — це один із найточніших методів тестування програмної логіки.

Він дає змогу:

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

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

День захисників і захисниць України

Ukrainian

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

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

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

Слава Україні!

Condition Testing

Condition Testing (тестування умов) — це структурний метод тестування програмного забезпечення, при якому тестуються логічні умови в коді з метою виявлення помилок у логіці.

Цей тип тестування належить до тестування білої скриньки (white-box testing), тобто, коли тестувальник має доступ до коду програми і перевіряє внутрішню логіку виконання.

Мета Condition Testing

Основні цілі:

  1. Перевірити логіку умовних виразів
    • Кожна частина складної умови повинна бути перевірена на істинність (true) та хибність (false).
  2. Забезпечити правильність роботи кожної окремої умови
  3. Збільшити покриття коду
    • Щоб усі логічні умови були перевірені, і в результаті — знайдено більше потенційних помилок.
  4. Забезпечити надійність програми
    • Особливо важливо для критичних систем (медицина, авіація, банківські системи).

Що таке умова (Condition)?

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

if (x > 0 && y < 10)

У цьому виразі є дві атомарні умови:

  1. x > 0
  2. y < 10

Вони об’єднані за допомогою логічного оператора && (AND).

Чому недостатньо просто перевірити весь if?

Можна протестувати, чи виконується if, але не перевірити, як поводить себе кожна умова окремо. Наприклад:

  • Якщо x > 0 завжди істинне у всіх тестах, ми не знаємо, як поводиться програма, коли x <= 0.
  • Якщо y < 10 завжди хибне — ми не перевіряємо гілку, де воно стає істинним.

Тестування лише результату if не гарантує правильності логіки усіх умов у виразі.

Що саме тестується в Condition Testing?

  • Кожна атомарна умова (елемент логічного виразу)
  • Перевіряється, чи вона може бути як true, так і false
  • Перевіряється, чи вона впливає на результат усього виразу

Види тестування умов

Види покриттяОпис
Condition CoverageКожна атомарна умова в логічному виразі перевіряється на true і false
Decision (Branch) CoverageПеревірка, що кожна гілка рішення (if, else, switch) виконується хоча б раз
Condition/Decision CoverageКомбіноване покриття — кожна умова і кожне рішення
MC/DC (Modified Condition/Decision Coverage)Перевірка, що кожна умова впливає на результат рішення незалежно

Приклад:

def check_discount(age, is_member):
    if age > 65 or is_member:
        return "Discount"
    else:
        return "No Discount"

Тут маємо 2 умови поєднані логічним оператором or:

  • age > 65
  • is_member

Щоб провести condition testing, потрібно створити такі тести:

Test Caseage > 65is_memberРезультат
1TrueFalseDiscount
2FalseTrueDiscount
3FalseFalseNo Discount
4TrueTrueDiscount

Тут кожна умова приймає значення true і false принаймні один раз.

Чому Condition Testing важливе?

  1. Знаходить логічні помилки, які не видно при поверхневому тестуванні.
  2. Гарантує, що кожен логічний елемент працює як треба
  3. Допомагає при розробці складних алгоритмів — особливо там, де є багато if/else, циклів, вкладених умов.

Підсумок

ПараметрОпис
Що це?Тестування атомарних умов у логічних виразах
МетаПеревірити, чи кожна умова працює як треба
Основна діяКожна умова тестується на true і false
ПеревагаЗнаходить логічні помилки на ранній стадії

Branch Testing

Branch testing — це техніка тестування програмного забезпечення, що полягає в перевірці кожної гілки умовних операторів (наприклад, if, else, switch) у програмі. Це метод, який дозволяє перевірити, чи будуть виконуватися всі можливі варіанти розгалужень в програмному коді.

Мета:

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

Як це працює?

У більшості мов програмування ми маємо умовні оператори або конструкції, які змінюють хід виконання програми в залежності від певних умов. Коли умова виконується, програма “розгалужується” на два або більше можливих шляхи виконання. Branch testing полягає в тому, щоб перевірити кожен з цих шляхів, щоб переконатися, що вони правильно обробляються.

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

Розглянемо функцію, яка перевіряє, чи є число позитивним:

def check_number(x):
    if x > 0:
        return "positive"
    else:
        return "non-positive"

У цьому коді є одне умовне розгалуження: перевірка умови if x > 0. Це розгалуження створює дві гілки:

  • Гілка 1: умова x > 0 істинна, тобто виконується код в першій частині if, і повертається "positive".
  • Гілка 2: умова якщо x > 0 не виконується, тобто є хибною, себто виконується код в блоці else, і повертається "non-positive".

Щоб провести branch testing, нам потрібно протестувати обидві гілки:

  • Один тест, де x > 0 (наприклад, x = 5).
  • Один тест, де x <= 0 (наприклад, x = -1 або x = 0).

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

Чому важливо тестувати кожну гілку?

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

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

Branch Coverage: як вимірюється ефективність?

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

Формула:

Branch coverage (%) = (Кількість виконаних гілок / Загальна кількість гілок) × 100%

Трохи складніший приклад:

def analyze_number(x):
    if x > 0:
        return "positive"
    elif x == 0:
        return "zero"
    else:
        return "negative"

Тут ми маємо 3 можливі гілки:

  1. x > 0 — це позитивна гілка.
  2. x == 0 — це гілка для нуля.
  3. x < 0 — це негативна гілка.

Щоб досягти 100% branch coverage, потрібно виконати 3 тести:

  • Один, де x > 0 (наприклад, x = 5).
  • Один, де x == 0 (наприклад, x = 0).
  • Один, де x < 0 (наприклад, x = -1).

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

Різниця між Branch Testing і Statement Testing

Statement testing та branch testing — це дві різні техніки:

  • Statement testing — перевіряє лише, чи виконуються всі окремі оператори (наприклад, if, return). У цьому випадку перевіряється, чи виконується сам оператор, незалежно від того, яким чином виконується умова.
  • Branch testing — перевіряє, чи були виконані всі можливі гілки умов, тобто чи перевірялися всі шляхи виконання програми, які можуть виникнути через умови.

Чи завжди достатньо branch testing?

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

  • Path testing: Перевірка всіх можливих шляхів виконання програми, що включає не тільки розгалуження, але й їх комбінації.
  • Condition coverage: Перевірка кожної умови, щоб вона була істинною та хибною.

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

Statement testing

Statement testing — це один із базових підходів до тестування програмного забезпечення, який належить до категорії white-box testing (тестування з доступом до коду). Його мета — перевірити, чи всі оператори (інструкції) у програмному коді були виконані хоча б один раз під час тестування.

Основна ідея

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

Приклад:

def is_positive(n):
    if n > 0:
        return True
    else:
        return False

Щоб покрити всі інструкції:

  • Нам потрібно перевірити випадок, коли n > 0 — виконається return True
  • І випадок, коли n <= 0 — виконається return False

Якщо протестувати лише з n = 5, то буде виконано лише return True, і покриття буде неповним.

Вимірювання

Результат statement testing часто виражається у відсотках покриття коду — statement coverage:

Statement Coverage = (Кількість виконаних інструкцій / Загальна кількість інструкцій) × 100%

Переваги:

  • Простий у реалізації.
  • Допомагає виявити “мертвий код” (який ніколи не виконується).

Недоліки:

  • Не гарантує покриття всіх умов або гілок (наприклад, не перевіряє всі варіанти if/else або циклів).
  • Може пропустити помилки, якщо інструкція виконується, але не в усіх логічних сценаріях.

Порівняння з іншими видами:

Тип тестуванняЩо перевіряє
Statement TestingЧи виконана кожна інструкція
Branch TestingЧи виконана кожна гілка (if/else)
Path TestingЧи пройдені всі можливі шляхи
Condition TestingЧи перевірені всі умови логіки

Підсумок

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