Model-Based Testing (MBT) представляет собой смену парадигмы в автоматизации тестирования, где тесты автоматически генерируются из абстрактных моделей поведения системы, а не пишутся вручную. Этот подход позволяет тестировщикам сфокусироваться на моделировании ожидаемого поведения, пока инструменты занимаются механической работой генерации и выполнения тестовых случаев.

Что такое Model-Based Testing?

Model-Based Testing использует формальные или полуформальные модели для представления ожидаемого поведения тестируемой системы. Эти модели—такие как машины состояний, UML диаграммы или таблицы решений—служат единым источником истины, из которого автоматически выводятся тестовые случаи, тестовые данные и ожидаемые результаты.

Ключевые Концепции

Модель: Абстрактное представление поведения системы, которое захватывает состояния, переходы, входные данные и ожидаемые выходные данные.

Алгоритм Генерации Тестов: Логика, которая обходит модель для создания тестовых путей, удовлетворяющих специфическим критериям покрытия.

Критерии Покрытия: Правила, определяющие насколько тщательно должна быть исследована модель (например, все состояния, все переходы, все пути).

Оракул: Механизм для определения ожидаемых результатов, выведенный напрямую из спецификации модели.

Типы Моделей в MBT

Модели Машин Состояний

Машины состояний превосходно подходят для моделирования систем с отчетливыми операционными режимами и переходами состояний.

# Пример: Модель машины состояний для системы входа
from graphwalker import Model, Edge, Vertex

class LoginModel(Model):
    def __init__(self):
        super().__init__()

        # Определить вершины (состояния)
        logged_out = Vertex("LoggedOut")
        login_page = Vertex("LoginPage")
        logged_in = Vertex("LoggedIn")
        locked_out = Vertex("LockedOut")

        # Определить рёбра (переходы)
        self.add_edge(Edge(logged_out, login_page, "navigateToLogin"))
        self.add_edge(Edge(login_page, logged_in, "loginSuccess"))
        self.add_edge(Edge(login_page, login_page, "loginFailure"))
        self.add_edge(Edge(login_page, locked_out, "threeFailedAttempts"))
        self.add_edge(Edge(logged_in, logged_out, "logout"))

        self.start_vertex = logged_out

UML Диаграммы Активности

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

Преимущества:

  • Визуальное представление потока процесса
  • Захватывает точки принятия решений и параллельные активности
  • Знакомая нотация для заинтересованных сторон
  • Поддерживает swimlanes для многоакторных сценариев

Таблицы Решений

Таблицы решений компактно представляют сложную условную логику с множественными комбинациями входных данных.

Попытки ВходаПароль КорректенСтатус АккаунтаРезультат
≤ 3ДаАктивенУспех
≤ 3НетАктивенНеудача
> 3ЛюбойАктивенБлокировка
ЛюбойЛюбойЗаблокированОшибка Блокировки
ЛюбойДаНеактивенОшибка Неактивного

Инструменты и Фреймворки MBT

GraphWalker (Java/Python)

GraphWalker генерирует тестовые последовательности, проходя по направленным графам, представляющим поведение системы.

// Определение модели GraphWalker
public class ShoppingCartModel implements Model {

    @Action
    public void e_AddItem() {
        // Действие: Добавить товар в корзину
        cart.addItem(testProduct);
    }

    @Action
    public void e_RemoveItem() {
        // Действие: Удалить товар из корзины
        cart.removeItem(testProduct);
    }

    @Action
    public void e_Checkout() {
        // Действие: Перейти к оформлению заказа
        cart.checkout();
    }

    @State
    public void v_EmptyCart() {
        // Проверка: Корзина пуста
        assertTrue(cart.isEmpty());
    }

    @State
    public void v_CartWithItems() {
        // Проверка: Корзина содержит товары
        assertFalse(cart.isEmpty());
    }

    @State
    public void v_CheckoutPage() {
        // Проверка: На странице оформления заказа
        assertTrue(page.isCheckoutPage());
    }
}

ModelJUnit (Java)

ModelJUnit использует Java код для специфицирования моделей и генерирует тесты используя случайные или жадные алгоритмы.

public class ElevatorModel implements FsmModel {
    private int floor = 0;
    private int target = 0;
    private boolean doorsOpen = false;

    public boolean selectFloorGuard() {
        return !doorsOpen;
    }

    @Action
    public void selectFloor() {
        target = random.nextInt(10);
    }

    @Action
    public void openDoors() {
        doorsOpen = true;
    }

    @Action
    public void closeDoors() {
        doorsOpen = false;
    }

    public boolean moveUpGuard() {
        return floor < target && !doorsOpen;
    }

    @Action
    public void moveUp() {
        floor++;
    }

    public boolean moveDownGuard() {
        return floor > target && !doorsOpen;
    }

    @Action
    public void moveDown() {
        floor--;
    }
}

Spec Explorer (Microsoft)

Spec Explorer специализируется на тестировании протоколов и валидации API используя Cord (C# для моделирования).

Ключевые Возможности:

  • Модельные программы написанные на C#
  • Стратегии исследования для пространства состояний
  • Нарезка и фильтрация тестовых случаев
  • Интеграция с Visual Studio

Критерии Покрытия

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

Покрытие Состояний

Посетить каждое состояние в модели хотя бы один раз.

Преимущество: Гарантирует, что все режимы системы протестированы Ограничение: Может упустить критические комбинации переходов

Покрытие Переходов

Выполнить каждый переход в модели хотя бы один раз.

Преимущество: Более тщательно чем покрытие состояний Размер Набора: Средний

Покрытие Путей

Выполнить все возможные пути через модель.

Преимущество: Всестороннее тестирование Ограничение: Часто неосуществимо из-за комбинаторного взрыва

Общие Практические Критерии

КритерийЦель ПокрытияРазмер НабораСлучай Использования
Покрытие СостоянийВсе состоянияМалыйSmoke тестирование
Покрытие ПереходовВсе переходыСреднийСтандартная регрессия
2-Way ПереходыВсе пары переходовБольшойТщательное тестирование
Покрытие Edge-PairВсе пары рёберБольшойКритические системы
Все ПутиВсе возможные путиЭкспоненциальныйТолько малые модели

Рабочий Процесс MBT

Шаг 1: Создание Модели

Проанализировать требования и создать абстрактную модель, захватывающую поведение системы.

# Пример: Модель банкомата на Python
class ATMModel:
    def __init__(self):
        self.state = "idle"
        self.balance = 1000
        self.pin_attempts = 0

    def insert_card(self):
        if self.state == "idle":
            self.state = "card_inserted"
            return True
        return False

    def enter_pin(self, correct):
        if self.state == "card_inserted":
            if correct:
                self.state = "authenticated"
                self.pin_attempts = 0
            else:
                self.pin_attempts += 1
                if self.pin_attempts >= 3:
                    self.state = "card_captured"
            return True
        return False

    def withdraw(self, amount):
        if self.state == "authenticated":
            if amount <= self.balance:
                self.balance -= amount
                return True
        return False

Шаг 2: Генерация Тестов

Настроить критерии покрытия и автоматически сгенерировать тестовые последовательности.

# Пример GraphWalker CLI
graphwalker offline \
  --model shopping-cart.json \
  --generator "random(edge_coverage(100))" \
  --output tests.json

Шаг 3: Выполнение Тестов

Выполнить сгенерированные тесты против реальной системы, сравнивая результаты с предсказаниями модели.

// Выполнить сгенерированную тестовую последовательность
GraphWalker walker = new GraphWalker(new ShoppingCartModel());
walker.setPathGenerator(new RandomPath(new EdgeCoverage(100)));

while (walker.hasNextStep()) {
    walker.getNextStep().execute();
    assertTrue(walker.getCurrentVertex().verify());
}

Шаг 4: Анализ и Уточнение

Проанализировать сбои для определения, находится ли дефект в системе или в модели.

Преимущества Model-Based Testing

Увеличенное Покрытие Тестов

Автоматическая генерация исследует пути, которые человеческие тестировщики могли бы упустить.

Пример из Практики: Телекоммуникационная компания, использующая MBT, увеличила покрытие переходов с 67% до 98%, обнаружив 12 ранее неизвестных дефектов.

Сокращенное Обслуживание

Обновите модель один раз; тесты перегенерируются автоматически.

Пример ROI: 60% сокращение усилий на обслуживание тестов при частых изменениях требований.

Более Раннее Обнаружение Дефектов

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

Влияние Shift-Left: 40% дефектов найдено на этапе моделирования, до существования кода.

Живая Документация

Модели служат исполняемыми спецификациями, которые никогда не устаревают.

Вызовы и Ограничения

Усилия на Создание Модели

Построение точных моделей требует значительных начальных инвестиций.

Смягчение: Начинать с критических рабочих процессов; расширять покрытие итеративно.

Кривая Обучения Инструментов

Инструменты MBT имеют более крутую кривую обучения чем скриптовые фреймворки.

Смягчение: Инвестировать в обучение; строить внутреннюю экспертизу постепенно.

Недетерминированные Системы

Системы с непредсказуемым поведением (например, тяжелые внешние зависимости) сложнее моделировать.

Смягчение: Моделировать на более высоких уровнях абстракции; использовать заглушки для внешних систем.

Валидность Модели

Модели могут расходиться с реальным поведением системы со временем.

Смягчение: Непрерывная валидация; автоматические проверки трассируемости модель-к-коду.

Лучшие Практики

Начинать с Малого

Начать с ограниченной модели, покрывающей основную функциональность.

# Начальная модель: Только базовая аутентификация пользователя
class MinimalAuthModel:
    states = ["logged_out", "logged_in"]
    transitions = [
        ("logged_out", "login_success", "logged_in"),
        ("logged_in", "logout", "logged_out")
    ]

Сотрудничать с Заинтересованными Сторонами

Вовлекать экспертов предметной области в проверку модели для обеспечения точности.

Техника: Разработка модели на основе воркшопов с бизнес-аналитиками и разработчиками.

Комбинировать с Традиционным Тестированием

Использовать MBT для сложной логики; использовать скриптовые тесты для простых случаев.

Гибридная Стратегия: 70% MBT для функций зависимых от состояния, 30% скриптовых для валидации UI.

Поддерживать Трассируемость Модели

Связывать элементы модели с требованиями для анализа влияния.

# Картирование трассируемости
transitions:
  - id: T1
    name: "login_success"
    requirements: [REQ-AUTH-001, REQ-AUTH-003]
  - id: T2
    name: "login_failure"
    requirements: [REQ-AUTH-002]

Контроль Версий Моделей

Обращаться с моделями как с первоклассными артефактами в системе контроля версий.

# Git структура для MBT
models/
  ├── authentication.graphml
  ├── shopping-cart.json
  └── payment-flow.yaml
tests/
  ├── generated/
  └── manual/

Применение в Реальном Мире

Тестирование Встроенных Систем

Автомобильный производитель использует MBT для тестирования ECU, генерируя тысячи тестовых случаев из машин состояний.

Результаты: 35% сокращение ускользнувших дефектов, 50% быстрее регрессионное тестирование.

Тестирование Web Приложений

E-commerce платформа моделирует потоки оформления заказа с 15 состояниями и 40 переходами.

Результаты: Обнаружено 8 крайних случаев, не покрытых ручными тестами.

Тестирование API

Финансовая компания моделирует переходы состояний REST API для обработки платежей.

Результаты: Достигнуто 100% покрытие переходов; модель служит документацией API.

Заключение

Model-Based Testing смещает фокус тестирования с отдельных тестовых случаев на всесторонние модели поведения. Несмотря на требование значительных начальных инвестиций в навыки моделирования и инструменты, MBT приносит существенные долгосрочные выгоды в покрытии, поддерживаемости и обнаружении дефектов—особенно для сложных систем с богатым поведением, зависимым от состояния.

Успех с MBT требует обращения с моделями как с живыми артефактами, поддержания их точности через непрерывное уточнение и валидацию против эволюционирующего поведения системы.