Mock временных функций

В тестировании веб-приложений часто возникает необходимость эмулировать различные сценарии, связанные с временем. Например, необходимо замедлить или ускорить время выполнения определённых функций, обработать тайм-ауты или имитировать различные временные зоны. Для таких задач полезно использовать методы для мокирования временных функций, таких как setTimeout, setInterval и Date. В WebdriverIO можно легко замокировать эти функции с помощью библиотеки, предоставляющей инструменты для изменения поведения времени в процессе тестирования.

Зачем нужен mock временных функций?

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

Основные подходы к мокированию времени

Для замены стандартных временных функций в WebdriverIO можно использовать различные подходы. Один из популярных методов — это использование библиотеки mockdate для замены текущей даты и времени, а также мокирование таких функций, как setTimeout, setInterval, clearTimeout, clearInterval с помощью sinon или других утилит.

Мокирование setTimeout и setInterval

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

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

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

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

const sinon = require('sinon');

describe('Mocking setTimeout and setInterval', () => {
    let clock;

    beforeEach(() => {
        // Создаем временной "часы", которые позволяют нам управлять временем
        clock = sinon.useFakeTimers();
    });

    afterEach(() => {
        // Восстанавливаем стандартное поведение временных функций
        clock.restore();
    });

    it('should mock setTimeout', () => {
        const callback = sinon.spy();

        // Используем замокированный setTimeout
        setTimeout(callback, 1000);

        // Прокачиваем время на 1 секунду
        clock.tick(1000);

        // Проверяем, что callback был вызван
        sinon.assert.calledOnce(callback);
    });

    it('should mock setInterval', () => {
        const callback = sinon.spy();

        // Замокированный setInterval
        setInterval(callback, 500);

        // Прокачиваем время на 1 секунду (два интервала должны быть вызваны)
        clock.tick(1000);

        // Проверяем, что callback был вызван дважды
        sinon.assert.calledTwice(callback);
    });
});

В этом примере используется sinon.useFakeTimers(), который позволяет замокировать стандартные временные функции, включая setTimeout и setInterval. Время не идёт в реальном масштабе, и мы можем вручную контролировать, когда произойдут события, используя clock.tick(). Это позволяет эффективно тестировать функции, которые зависят от времени, без реальной задержки.

Мокирование текущей даты с помощью mockdate

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

Использование mockdate

Библиотека mockdate позволяет задавать фиксированную дату и время для тестов, что удобно, когда нужно тестировать работу приложения с определённым временем. Например, можно проверить, как приложение ведёт себя, если оно запущено в определённый момент.

Пример использования mockdate:

const mockdate = require('mockdate');

describe('Mocking current date with mockdate', () => {
    beforeEach(() => {
        // Устанавливаем фиксированную дату и время
        mockdate.set('2023-01-01');
    });

    afterEach(() => {
        // Восстанавливаем текущее время
        mockdate.reset();
    });

    it('should use the mocked date', () => {
        const currentDate = new Date();

        // Проверяем, что текущая дата равна заданной
        assert.strictEqual(currentDate.getFullYear(), 2023);
        assert.strictEqual(currentDate.getMonth(), 0); // Январь
        assert.strictEqual(currentDate.getDate(), 1); // 1 января
    });
});

В этом примере mockdate.set() устанавливает фиксированную дату, которая будет использоваться в тестах вместо реальной текущей даты и времени. После завершения тестов вызывается mockdate.reset(), чтобы вернуть систему к нормальной работе с настоящим временем.

Комбинированный подход

Иногда бывает необходимо использовать как мокирование времени с помощью sinon, так и фиксацию текущей даты с помощью mockdate. Это даёт полное управление над временем в тестах, позволяя эффективно эмулировать различные временные условия.

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

const sinon = require('sinon');
const mockdate = require('mockdate');

describe('Combined use of mockdate and sinon', () => {
    let clock;

    beforeEach(() => {
        // Устанавливаем фиксированную дату
        mockdate.set('2023-01-01');
        // Мокируем временные функции
        clock = sinon.useFakeTimers();
    });

    afterEach(() => {
        mockdate.reset();
        clock.restore();
    });

    it('should handle mocked date and time', () => {
        const callback = sinon.spy();

        // Замокированный setTimeout
        setTimeout(callback, 1000);

        // Прокачиваем время на 1 секунду
        clock.tick(1000);

        // Проверяем, что callback был вызван
        sinon.assert.calledOnce(callback);
        // Проверяем, что дата остается замокированной
        const currentDate = new Date();
        assert.strictEqual(currentDate.getFullYear(), 2023);
        assert.strictEqual(currentDate.getMonth(), 0); // Январь
        assert.strictEqual(currentDate.getDate(), 1); // 1 января
    });
});

Преимущества использования mock временных функций

  1. Ускорение тестирования: Замена реального времени позволяет избежать длительных ожиданий в тестах, таких как задержки в 1 секунду или несколько минут.

  2. Повторяемость: Замокированные временные функции обеспечивают воспроизводимость тестов, так как время можно точно контролировать.

  3. Гибкость: Возможность тестировать различные сценарии с разными временными условиями (например, в разных временных зонах или с разными интервалами) значительно повышает покрытие тестами.

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

Заключение

Мокирование временных функций в WebdriverIO позволяет значительно упростить тестирование приложений, которые зависят от времени. С помощью таких инструментов, как sinon и mockdate, можно легко заменять стандартное поведение времени, ускорять выполнение тестов и точно эмулировать различные временные условия. Этот подход предоставляет тестировщикам гибкость и контроль, позволяя создавать более эффективные и надежные тесты.