Мокирование зависимостей

В процессе тестирования веб-приложений с использованием Playwright часто возникает необходимость изолировать тестируемый компонент от внешних зависимостей, таких как API, базы данных или сторонние сервисы. Это позволяет тестировать приложение в условиях, когда влияние внешних систем минимизировано или полностью исключено. Одним из эффективных методов для достижения этой цели является мокирование зависимостей.

Что такое мокирование?

Мокирование (mocking) — это создание поддельных (моковых) объектов, которые имитируют поведение настоящих объектов, не вызывая реальные взаимодействия с ними. Мокирование позволяет контролировать ответы на запросы, подменяя работу с реальными внешними системами, что делает тесты более предсказуемыми и быстрыми.

Зачем нужно мокирование в Playwright?

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

  • Зависимость от сторонних API, которые могут быть нестабильны или медленно реагировать.
  • Высокая стоимость использования реальных данных из внешних систем, например, при запросах к базе данных или API.
  • Необходимость повторного тестирования сценариев с одними и теми же входными данными, что может потребовать большого количества однотипных запросов.

Мокирование помогает решить эти проблемы, подменяя реальные вызовы с внешними сервисами на заранее определенные ответы. Таким образом, тестирование становится более предсказуемым, стабильным и быстрым.

Мокирование запросов в Playwright

Playwright предоставляет мощный механизм для мокирования сетевых запросов и ответов. Основной инструмент для этого — метод page.route(), который позволяет перехватывать запросы, отправляемые браузером, и перенаправлять их или изменять.

Основной синтаксис

await page.route('**/api/*', (route, request) => {
  // Здесь можно подменить ответ на запрос
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify({ data: 'mocked data' }),
  });
});

В этом примере при любом запросе, который соответствует паттерну **/api/*, Playwright перехватывает его и отправляет мокированный ответ с кодом 200 и JSON-данными. Важно отметить, что метод route.fulfill() позволяет полностью контролировать ответ, включая статус, заголовки и тело.

Использование моков с асинхронными запросами

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

await page.route('**/api/user', async (route, request) => {
  const response = await fetch('https://mockapi.com/user');
  const data = await response.json();
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify(data),
  });
});

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

Условия мокирования

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

Пример мокирования с проверкой заголовков:

await page.route('**/api/*', (route, request) => {
  if (request.headers()['Authorization'] === 'Bearer mock_token') {
    route.fulfill({
      status: 200,
      contentType: 'application/json',
      body: JSON.stringify({ message: 'Authenticated' }),
    });
  } else {
    route.abort(); // Отклонить запрос
  }
});

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

Мокирование и тестирование разных типов запросов

При тестировании веб-приложений может возникать необходимость мокировать различные типы HTTP-запросов: GET, POST, PUT, DELETE. Playwright поддерживает все эти методы, и для каждого из них можно настроить отдельное мокирование.

Мокирование GET-запросов

await page.route('**/api/products', (route, request) => {
  route.fulfill({
    status: 200,
    contentType: 'application/json',
    body: JSON.stringify([{ id: 1, name: 'Mock Product' }]),
  });
});

Мокирование POST-запросов

await page.route('**/api/orders', (route, request) => {
  const postData = JSON.parse(request.postData());
  if (postData.productId === 1) {
    route.fulfill({
      status: 201,
      contentType: 'application/json',
      body: JSON.stringify({ orderId: 123 }),
    });
  } else {
    route.abort();
  }
});

Интеграция моков с тестами

Для эффективного тестирования мокирование часто используется в сочетании с фреймворками для тестирования, такими как Jest или Mocha. Playwright можно интегрировать с этими фреймворками, создавая тесты, которые управляют состоянием моков и проверяют корректность работы приложения в условиях замены внешних зависимостей.

Пример интеграции с Jest:

const { chromium } = require('playwright');

describe('Test with mocks', () => {
  let browser;
  let page;

  beforeAll(async () => {
    browser = await chromium.launch();
    page = await browser.newPage();
  });

  afterAll(async () => {
    await browser.close();
  });

  test('should display mocked products', async () => {
    await page.route('**/api/products', (route) => {
      route.fulfill({
        status: 200,
        contentType: 'application/json',
        body: JSON.stringify([{ id: 1, name: 'Mock Product' }]),
      });
    });

    await page.goto('http://localhost:3000');
    const productName = await page.textContent('.product-name');
    expect(productName).toBe('Mock Product');
  });
});

В этом примере используется Jest для организации тестов, а Playwright — для мокирования запросов. Тест проверяет, что на странице отображается мокированный продукт.

Проблемы и ограничения мокирования

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

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

Заключение

Мокирование зависимостей в Playwright — это мощный способ ускорить тестирование веб-приложений, минимизируя влияние внешних систем. Используя методы page.route(), можно перехватывать и подменять запросы, проверять их параметры, а также создавать асинхронные моки для более сложных сценариев. Важно помнить о возможных ограничениях мокирования и использовать его в сочетании с другими видами тестирования для достижения максимальной надежности приложений.