Мокирование API

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

Сценарии применения моков

Использование моков API необходимо, когда:

  • требуется эмулировать ответы сервера, не поднимая реальный backend;
  • нужно проверять обработку ошибок, таймаутов или специфичных статусов HTTP;
  • важно ускорить выполнение большого набора тестов;
  • необходимо протестировать логику ретраев, кэширования и агрегации данных.

Инструменты для мокирования

В экосистеме JavaScript наибольшее распространение получили Sinon.js, Jasmine Spies и встроенные механизмы фреймворков тестирования. При использовании Karma выбор инструмента зависит от предпочтений и стека проекта.

Sinon.js предоставляет фейки для XMLHttpRequest, таймеров и функций. Это удобно, когда код активно использует классические XHR-запросы или setTimeout. Jasmine Spies позволяет перехватывать вызовы функций и задавать ожидаемые результаты, а также проверять количество вызовов и аргументы. В случае, когда приложение использует современный fetch, можно применить специальные моки через sinon.fake() или через патчинг глобального объекта window.fetch.

Архитектурный подход к мокам

Выстраивание корректной архитектуры мокирования требует ясной границы между тестируемой логикой и адаптерами к API. Инкапсуляция HTTP-клиента в отдельный модуль облегчает подмену этого слоя в тестах. Вместо создания моков для каждой сетевой операции полезно абстрагировать транспорт и тестировать только бизнес-логику.

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

Пример применения Sinon с Karma

describe('Service: UserService', function() {
  var xhr, requests, service;

  beforeEach(function() {
    xhr = sinon.useFakeXMLHttpRequest();
    requests = [];
    xhr.onCREATE = function(req) { requests.push(req); };

    module('app');
    inject(function(_UserService_) {
      service = _UserService_;
    });
  });

  afterEach(function() {
    xhr.restore();
  });

  it('должен получать профиль пользователя', function(done) {
    service.getProfile(42).then(function(profile) {
      expect(profile.id).toBe(42);
      expect(profile.name).toBe('Alice');
      done();
    });

    requests[0].respond(
      200,
      { 'Content-Type': 'application/json' },
      JSON.stringify({ id: 42, name: 'Alice' })
    );
  });
});

В данном примере используется подмена XMLHttpRequest средствами Sinon. Через respond формируется ответ сервера, а дальнейшая обработка тестируется без реального сетевого вызова. Karma обеспечивает контроль запуска браузера и сбор отчетов, а Sinon отвечает за управление сетевым слоем.

Мокирование fetch и промисов

Современные приложения чаще используют fetch. В этом случае подмена осуществляется через фейковую функцию, возвращающую промис:

window.fetch = sinon.fake.resolves(
  new Response(JSON.stringify({ status: 'ok' }), {
    status: 200,
    headers: { 'Content-Type': 'application/json' }
  })
);

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

Работа с ошибками и таймингами

Тестирование ошибок сервера требует моков с отказами (reject) или статусами 4xx/5xx. Для тестирования таймаутов Sinon предоставляет фейковые таймеры, позволяющие управлять временем в тестах и синхронно проверять асинхронную логику.

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

Организация данных моков

Для крупных проектов рекомендуется выделять каталоги с фикстурами ответов API. Это уменьшает дублирование данных, повышает читаемость тестов и облегчает поддержку. Фикстуры должны быть описательными и актуальными относительно API.

Пример структуры проекта:

test/
  fixtures/
    user/
      profile.json
      preferences.json
    billing/
      invoice.json
  unit/
    userService.spec.js
    billingService.spec.js

Фикстуры подключаются в тесты и используются для формирования ответов.

Взаимодействие с Karma и preprocessors

Karma поддерживает множество препроцессоров, которые могут подгружать JSON-файлы фикстур и отдавать их в тесты как модули. Это упрощает мокирование API и снижает объем ручной работы. В конфигурации Karma возможно указать препроцессоры для JSON, чтобы использовать их как обычные объекты.

Избежание сверхмокирования

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

Детерминизм и репликация сложных сценариев

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

Выводы для практики тестирования

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