Mock запросы в тестах

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

Зачем моки в тестах?

Мокирование запросов позволяет:

  • Изолировать тестируемую логику от внешних сервисов. Это необходимо, когда внешний сервис нестабилен или его недоступность мешает тестированию.
  • Контролировать данные. Мокирование запросов позволяет заранее определить, какие данные будет возвращать сервер, что особенно важно для проверки обработки ошибок, необычных данных и других нештатных ситуаций.
  • Ускорить выполнение тестов. Вместо того, чтобы ожидать реальных ответов от серверов, моки могут вернуть данные моментально, что снижает время выполнения тестов.
  • Повторяемость тестов. Моки гарантируют одинаковые результаты при каждом прогоне тестов, независимо от состояния внешних сервисов или изменений в их данных.

Мокирование запросов с использованием WebdriverIO

WebdriverIO предоставляет несколько подходов для мокирования HTTP-запросов, начиная от использования встроенной функциональности, такой как browser.mock(), до интеграции с различными внешними библиотеками для создания моков.

Использование browser.mock()

WebdriverIO поддерживает мокирование запросов через API browser.mock(), которое позволяет перехватывать запросы и задавать нужные ответы. Это позволяет не только тестировать успешные сценарии, но и обрабатывать ошибки, тайм-ауты и другие исключительные ситуации.

Пример мока HTTP-запроса:

describe('Mocking requests in WebDriverIO', () => {
    it('should mock an API response', async () => {
        // Создаем мок на запрос к /api/data
        await browser.mock('GET', '/api/data', (req) => {
            req.respond({
                status: 200,
                body: { message: 'Mocked response' }
            });
        });

        // Ожидаем, что запрос будет успешно обработан
        const response = await browser.url('/test-page'); 

        // Проверяем, что приложение использует моки
        const message = await browser.$('.message').getText();
        expect(message).toEqual('Mocked response');
    });
});

В данном примере мы создаем мок для GET-запроса на путь /api/data, и когда запрос будет выполнен, сервер вернет статус 200 и тело ответа с полем message, равным Mocked response. В тесте мы проверяем, что текст на странице соответствует этому значению.

Мокирование запросов с использованием библиотек

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

Пример использования библиотеки nock для мока API запросов:

const nock = require('nock');

describe('Mocking HTTP requests with nock', () => {
    it('should mock an API request with nock', async () => {
        // Создаем мок на запрос к /api/data
        nock('http://localhost')
            .get('/api/data')
            .reply(200, { message: 'Mocked with nock' });

        // Ожидаем, что запрос будет выполнен и вернется мокированный ответ
        await browser.url('/test-page'); 

        // Проверяем, что приложение использует моки
        const message = await browser.$('.message').getText();
        expect(message).toEqual('Mocked with nock');
    });
});

В этом примере библиотека nock перехватывает запросы, отправленные на http://localhost/api/data, и возвращает заранее заданный ответ. Это может быть полезно для более детализированного управления запросами и ответами.

Управление ошибками при мокировании

Мокирование также полезно для проверки поведения системы в случае ошибок. WebdriverIO позволяет задавать не только успешные ответы, но и ошибки серверов, такие как 404 или 500. Это позволяет убедиться, что приложение корректно обрабатывает неудачные запросы.

Пример обработки ошибки с мокированием:

describe('Mocking error responses', () => {
    it('should handle a 500 error from the API', async () => {
        // Мокаем ответ с ошибкой 500
        await browser.mock('GET', '/api/data', (req) => {
            req.respond({
                status: 500,
                body: { error: 'Internal Server Error' }
            });
        });

        // Ожидаем, что ошибка будет обработана и отображена на странице
        const errorMessage = await browser.$('.error-message').getText();
        expect(errorMessage).toEqual('Internal Server Error');
    });
});

В данном случае мы задаем ответ с кодом 500 и текстом ошибки. Тест проверяет, что приложение корректно отображает сообщение об ошибке, которое приходит от сервера.

Тайм-ауты и задержки

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

Пример с задержкой:

describe('Mocking slow requests', () => {
    it('should handle slow responses with a timeout', async () => {
        // Создаем мок с задержкой
        await browser.mock('GET', '/api/data', (req) => {
            setTimeout(() => {
                req.respond({
                    status: 200,
                    body: { message: 'Slow response' }
                });
            }, 2000); // Задержка 2 секунды
        });

        // Ожидаем, что система обработает ответ через 2 секунды
        const message = await browser.$('.message').getText();
        expect(message).toEqual('Slow response');
    });
});

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

Очистка моков

После завершения тестов важно очистить все созданные моки, чтобы они не влияли на другие тесты. В WebdriverIO это можно сделать с помощью метода browser.mockClear(), который удаляет все зарегистрированные моки.

Пример очистки моков:

describe('Clear mocks after test', () => {
    it('should clear mocks after each test', async () => {
        await browser.mock('GET', '/api/data', (req) => {
            req.respond({ status: 200, body: { message: 'Test' } });
        });

        // Очистить все моки после выполнения теста
        await browser.mockClear();
    });
});

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

Преимущества мокирования запросов

  1. Повторяемость тестов — тесты становятся независимыми от внешних факторов.
  2. Снижение времени выполнения тестов — моки позволяют избежать длительных ожиданий при обращении к внешним сервисам.
  3. Контроль над тестируемыми данными — можно легко имитировать ответы с любыми данными, что позволяет проверять различные сценарии обработки информации.
  4. Тестирование ошибок — моки дают возможность проверять реакции системы на ошибки, такие как 404, 500 и другие.

Использование моков в WebdriverIO значительно расширяет возможности для создания стабильных и надежных тестов. Мокирование запросов позволяет тестировать как нормальные сценарии, так и нестандартные, связанные с ошибками, задержками или изменениями данных.