Lesson 17 of 26

Урок 17 — Техники тестирования: BVA и Equivalence Partitioning

Название: Boundary Value Analysis и Equivalence Partitioning — как тестировать меньше, но лучше
Описание: Разбираем две ключевые техники тест-дизайна: анализ граничных значений (BVA) и разбиение на классы эквивалентности (EP). Это основа грамотного проектирования тест-кейсов.
Почему это важно для QA: Без этих техник QA либо тестирует слишком много (лишняя работа), либо слишком мало (пропускает баги). BVA и EP — это математически обоснованный подход к выбору тестовых данных.


1. Проблема: как выбрать тестовые данные?

Предположим, есть поле «Возраст» при регистрации. Допустимый диапазон: 18 до 99 лет.

Наивный подход — проверить все возможные значения: 1, 2, 3, 4... 99, 100, 101...

Это невозможно. Значений слишком много.

Умный подход — использовать EP и BVA, чтобы выбрать минимальное количество тестов с максимальным покрытием.


2. Equivalence Partitioning (EP) — Разбиение на классы эквивалентности

Идея

Разделить все возможные входные данные на группы (классы), внутри которых система ведёт себя одинаково. Достаточно протестировать одно значение из каждого класса.

Принцип

Если система корректно обрабатывает одно значение из класса, она корректно обработает любое другое значение из того же класса.

Пример: поле «Возраст» (допустимо: 18–99)

Определяем классы:

Класс 1 (Invalid — слишком мало):  значения меньше 18
Класс 2 (Valid — допустимые):      значения от 18 до 99
Класс 3 (Invalid — слишком много): значения больше 99

Тест-кейсы:

TC-01: Возраст = 10  (из класса 1 — невалидный)  → Ожидаем: ошибка
TC-02: Возраст = 50  (из класса 2 — валидный)    → Ожидаем: принято
TC-03: Возраст = 110 (из класса 3 — невалидный)  → Ожидаем: ошибка

Итого: 3 теста вместо возможных тысяч. При этом покрываем все классы поведения.

Пример: поле «Email»

Класс 1 (Валидный):   user@domain.com
Класс 2 (Невалидный): без знака @
Класс 3 (Невалидный): без домена
Класс 4 (Невалидный): только пробелы
Класс 5 (Невалидный): пустое поле

Тест-кейсы:
TC-01: "user@test.com"  → OK
TC-02: "usertestcom"    → Ошибка
TC-03: "user@"          → Ошибка
TC-04: "   "            → Ошибка
TC-05: ""               → Ошибка

3. Boundary Value Analysis (BVA) — Анализ граничных значений

Идея

Большинство ошибок в коде происходит на границах допустимых диапазонов. BVA — это техника, которая фокусируется именно на граничных значениях.

Почему ошибки на границах?

Потому что разработчики часто допускают ошибку «на один» (off-by-one error):

javascriptjavascript
// Ошибка: < вместо <=
if (age < 18) showError();     // Пользователь с возрастом 18 видит ошибку
// Правильно: 
if (age < 18) showError();     // 17 → ошибка, 18 → ОК ✓

// Ошибка: <= вместо <
if (age <= 18) showError();    // 18 тоже даёт ошибку — неверно

Что тестировать по BVA

Для диапазона от min до max тестируем:

  • min - 1 — значение ниже минимума
  • min — минимально допустимое значение
  • min + 1 — чуть выше минимума
  • max - 1 — чуть ниже максимума
  • max — максимально допустимое значение
  • max + 1 — значение выше максимума

Пример: поле «Возраст» (допустимо: 18–99)

Граничные значения:
BVA-01: Возраст = 17  (min - 1) → Ожидаем: ОШИБКА
BVA-02: Возраст = 18  (min)     → Ожидаем: ОК
BVA-03: Возраст = 19  (min + 1) → Ожидаем: ОК
BVA-04: Возраст = 98  (max - 1) → Ожидаем: ОК
BVA-05: Возраст = 99  (max)     → Ожидаем: ОК
BVA-06: Возраст = 100 (max + 1) → Ожидаем: ОШИБКА

6 тестов — все критические граничные случаи покрыты.


4. EP + BVA вместе — полный набор тестов

На практике EP и BVA используются вместе: EP определяет классы, BVA выбирает значения на границах.

Поле «Скидка» (допустимо: 0% до 100%, целые числа)

Шаг 1: Определяем классы (EP)

Класс 1 (Invalid): значения < 0
Класс 2 (Valid):   значения от 0 до 100
Класс 3 (Invalid): значения > 100
Класс 4 (Invalid): нецелые числа (дробные)
Класс 5 (Invalid): нечисловые значения (текст)

Шаг 2: Добавляем граничные значения (BVA)

TC-01: -1       (EP класс 1, BVA min-1)   → ОШИБКА
TC-02: 0        (EP класс 2, BVA min)     → ОК (скидка 0%)
TC-03: 1        (EP класс 2, BVA min+1)   → ОК
TC-04: 50       (EP класс 2, середина)    → ОК
TC-05: 99       (EP класс 2, BVA max-1)   → ОК
TC-06: 100      (EP класс 2, BVA max)     → ОК (скидка 100%)
TC-07: 101      (EP класс 3, BVA max+1)   → ОШИБКА
TC-08: 50.5     (EP класс 4)              → ОШИБКА
TC-09: "abc"    (EP класс 5)              → ОШИБКА
TC-10: ""       (EP класс 5, пустое)      → ОШИБКА

10 тестов — полное покрытие всех классов и граничных значений.


5. Практический пример: форма регистрации

Поле «Пароль» (правила: 8–20 символов)

EP классы:

КлассОписаниеПример
Слишком короткий< 8 символов"abc"
Валидный8–20 символов"SecurePass1"
Слишком длинный> 20 символов21-символьная строка

BVA + EP тесты:

TC-01: 7 символов  "1234567"              → ОШИБКА (min - 1)
TC-02: 8 символов  "12345678"             → ОК (min)
TC-03: 9 символов  "123456789"            → ОК (min + 1)
TC-04: 14 символов "12345678901234"       → ОК (середина)
TC-05: 19 символов "1234567890123456789"  → ОК (max - 1)
TC-06: 20 символов "12345678901234567890" → ОК (max)
TC-07: 21 символ   21 символ             → ОШИБКА (max + 1)

6. Автоматизация в Playwright

typescripttypescript
import { test, expect } from "@playwright/test";
import { RegistrationPage } from "../pages/RegistrationPage";

// Тестовые данные — классы эквивалентности для поля "Возраст"
const AGE_TEST_CASES = [
  // EP + BVA граничные значения
  { age: 17,  expectedResult: "error",   description: "возраст ниже минимума (min-1)" },
  { age: 18,  expectedResult: "success", description: "минимально допустимый возраст (min)" },
  { age: 19,  expectedResult: "success", description: "чуть выше минимума (min+1)" },
  { age: 50,  expectedResult: "success", description: "середина допустимого диапазона" },
  { age: 98,  expectedResult: "success", description: "чуть ниже максимума (max-1)" },
  { age: 99,  expectedResult: "success", description: "максимально допустимый возраст (max)" },
  { age: 100, expectedResult: "error",   description: "возраст выше максимума (max+1)" },
] as const;

test.describe("EP + BVA: поле Возраст при регистрации", () => {
  for (const testCase of AGE_TEST_CASES) {
    test(`возраст ${testCase.age}: ${testCase.description}`, async ({ page }) => {
      const regPage = new RegistrationPage(page);
      await regPage.goto();
      await regPage.fillAge(testCase.age);
      await regPage.clickSubmit();

      if (testCase.expectedResult === "success") {
        await expect(regPage.ageError, `Возраст ${testCase.age} должен быть принят`).not.toBeVisible();
      } else {
        await expect(regPage.ageError, `Возраст ${testCase.age} должен вызвать ошибку`).toBeVisible();
      }
    });
  }
});

7. Decision Table — Таблица решений (дополнительная техника)

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

Пример: скидка на заказ

Условия:
- Пользователь — VIP?
- Сумма заказа > 5000 ₽?

            | TC1 | TC2 | TC3 | TC4 |
─────────────┼─────┼─────┼─────┼─────
VIP          |  Да |  Да | Нет | Нет |
Сумма > 5000 |  Да | Нет |  Да | Нет |
─────────────┼─────┼─────┼─────┼─────
Скидка 30%   |  ✓  |     |     |     |
Скидка 20%   |     |  ✓  |     |     |
Скидка 10%   |     |     |  ✓  |     |
Без скидки   |     |     |     |  ✓  |

8. Когда применять какую технику

СитуацияТехника
Числовые диапазоны, ограничения длиныBVA
Категории входных данныхEP
Несколько условий влияют на результатDecision Table
Последовательность действийState Transition
Всего несколько значенийAll-combinations

Итог

EQUIVALENCE PARTITIONING (EP)
├── Идея: разделить данные на классы с одинаковым поведением
├── Тестируем: одно значение из каждого класса
└── Экономим: не тестируем все возможные значения

BOUNDARY VALUE ANALYSIS (BVA)
├── Идея: ошибки чаще всего на границах диапазона
├── Тестируем: min-1, min, min+1, max-1, max, max+1
└── Ловим: off-by-one ошибки разработчиков

ВМЕСТЕ:
EP определяет классы → BVA выбирает значения на границах классов
= минимальное количество тестов, максимальное покрытие