Моки и стабы

В контексте тестирования JavaScript-приложений моки (mocks) и стабы (stubs) играют ключевую роль при эмуляции поведения функций, объектов или внешних зависимостей. Библиотека jQuery активно используется в таких сценариях для взаимодействия с DOM, отправки AJAX-запросов и обработки событий, поэтому правильное применение моков и стабов позволяет изолировать логику и повысить надёжность тестов.


Стабы в jQuery

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

  • Подставлять заранее определённые данные вместо реальных ответов.
  • Контролировать поведение сторонних функций.
  • Исключать побочные эффекты при тестировании (например, сетевые запросы).

Пример использования стабов с jQuery AJAX:

// Настоящая функция, вызывающая AJAX
function loadUserData(userId) {
    return $.ajax({
        url: `/api/users/${userId}`,
        method: 'GET'
    });
}

// Стаб функции $.ajax для тестирования
var ajaxStub = sinon.stub($, 'ajax').resolves({ id: 1, name: 'Иван' });

// Вызов функции
loadUserData(1).then(data => {
    console.log(data.name); // Выведет 'Иван'
});

// После теста восстанавливаем оригинальный метод
ajaxStub.restore();

В примере используется библиотека Sinon.js, совместимая с jQuery. Ключевой момент — стаб полностью заменяет вызов $.ajax, позволяя работать с заранее определённым результатом.


Моки в jQuery

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

  • Сколько раз вызывалась.
  • С какими аргументами.
  • В каком контексте.

Пример создания мока для метода jQuery:

// Мок для обработчика клика
var clickMock = sinon.mock($('#button'));

clickMock.expects('trigger').once().withArgs('click');

// Вызов метода
$('#button').trigger('click');

// Проверка, соответствует ли вызов ожиданиям
clickMock.verify();

// Восстановление оригинального объекта
clickMock.restore();

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


Совмещение стабов и моков для AJAX

Частой задачей является тестирование кода, который выполняет несколько AJAX-запросов и обновляет DOM на основе их результатов. В этом случае удобно комбинировать стабы и моки:

// Функция, обновляющая список пользователей
function renderUsers() {
    $.ajax({ url: '/api/users' })
        .done(function(users) {
            var list = $('#user-list');
            list.empty();
            users.forEach(u => list.append(`<li>${u.name}</li>`));
        });
}

// Стаб для $.ajax
var ajaxStub = sinon.stub($, 'ajax').resolves([{ id: 1, name: 'Иван' }, { id: 2, name: 'Мария' }]);

// Мок для контейнера списка
var listMock = sinon.mock($('#user-list'));
listMock.expects('append').twice();

// Вызов функции
renderUsers();

// Проверка моков
listMock.verify();
ajaxStub.restore();
listMock.restore();

Здесь $.ajax возвращает фиктивные данные, а мок проверяет, что DOM обновился корректно.


Особенности применения

  1. Изоляция зависимостей — моки и стабы позволяют тестировать только конкретную логику без реального взаимодействия с сервером или сложными объектами DOM.
  2. Контроль последовательности вызовов — моки дают возможность убедиться, что функции вызываются в правильном порядке.
  3. Управление асинхронностью — с помощью стабов можно синхронно возвращать результаты асинхронных операций, упрощая тесты.
  4. Совместимость с jQuery — большинство инструментов, таких как Sinon.js, легко интегрируются с jQuery-объектами и событиями.

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

  • Всегда восстанавливать оригинальные функции после теста (restore) во избежание побочных эффектов.
  • Использовать стабы для имитации данных, а моки — для проверки взаимодействий.
  • Ограничивать область действия моков и стабов, чтобы они не затрагивали глобальные объекты jQuery без необходимости.
  • Применять цепочки .resolves() или .rejects() для асинхронных методов, чтобы покрывать все сценарии.

Моки и стабы обеспечивают точный контроль над поведением функций и событий в jQuery-приложениях, позволяют тестировать сложную логику без обращения к реальным серверам и минимизируют побочные эффекты. Правильное их использование повышает надёжность тестов и упрощает сопровождение кода.