Создание шпионов

Шпионы — это функции, которые позволяют отслеживать вызовы других функций в процессе тестирования, не изменяя их поведение. В Mocha шпионы могут быть полезны для проверки того, были ли вызваны определённые методы, какие аргументы были переданы, а также для анализа результатов этих вызовов. Mocha не предоставляет собственных инструментов для создания шпионов, однако это можно сделать с помощью библиотеки Sinon, которая отлично интегрируется с Mocha и является стандартом де-факто для мокирования, шпионов и стабов в JavaScript.

Использование Sinon для создания шпионов

Для того чтобы начать использовать шпионов, необходимо сначала установить и подключить Sinon. Сначала можно установить Sinon с помощью npm:

npm install --save-dev sinon

После установки, в коде теста, необходимо импортировать Sinon:

const sinon = require('sinon');

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

Простейший пример шпиона

Для того чтобы создать шпион на функцию, достаточно использовать sinon.spy():

const myObject = {
  myMethod: function (x, y) {
    return x + y;
  }
};

describe('Шпион для функции', function () {
  it('должен отслеживать вызовы функции', function () {
    const spy = sinon.spy(myObject, 'myMethod');

    myObject.myMethod(2, 3);

    // Проверка, что метод был вызван
    sinon.assert.calledOnce(spy);

    // Проверка аргументов, с которыми был вызван метод
    sinon.assert.calledWith(spy, 2, 3);
  });
});

В примере выше создается шпион для метода myMethod объекта myObject. После вызова функции, можно проверить с помощью sinon.assert такие моменты, как:

  • calledOnce — проверка, был ли метод вызван ровно один раз.
  • calledWith — проверка, с какими аргументами был вызван метод.

Шпион без изменения оригинальной функции

Шпион можно создать не изменяя оригинальную функцию, что особенно полезно для проверки сторонних библиотек или встроенных методов, где нельзя изменить поведение:

const spy = sinon.spy();
spy(1, 2, 3);

// Проверка вызова
sinon.assert.calledOnce(spy);

// Проверка аргументов
sinon.assert.calledWith(spy, 1, 2, 3);

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

Удаление шпиона

После завершения теста, важно удалить шпиона, чтобы избежать влияния на другие тесты. Для этого можно использовать метод restore():

myObject.myMethod.restore();

Эта операция восстанавливает оригинальную функцию, которая была шпионена.

Проверка числа вызовов

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

const spy = sinon.spy();

spy();
spy();
spy();

sinon.assert.callCount(spy, 3);  // Проверка, что метод был вызван 3 раза

Метод callCount позволяет точно узнать, сколько раз была вызвана функция, на которой установлен шпион.

Шпионы для объектов и классов

Шпионов можно использовать не только для простых функций, но и для методов объектов или классов. Например, можно создать шпион для метода класса:

class MyClass {
  doSomething(x) {
    return x * 2;
  }
}

describe('Шпион для метода класса', function () {
  it('должен отслеживать вызов метода', function () {
    const myInstance = new MyClass();
    const spy = sinon.spy(myInstance, 'doSomething');

    myInstance.doSomething(5);

    sinon.assert.calledOnce(spy);
    sinon.assert.calledWith(spy, 5);
  });
});

Шпионы для асинхронных функций

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

const asyncFunction = function (callback) {
  setTimeout(function () {
    callback('done');
  }, 100);
};

describe('Шпион для асинхронной функции', function () {
  it('должен отслеживать вызов callback', function (done) {
    const spy = sinon.spy();

    asyncFunction(spy);

    setTimeout(function () {
      sinon.assert.calledOnce(spy);
      sinon.assert.calledWith(spy, 'done');
      done();
    }, 150);
  });
});

Шпионы и временные функции

Временные функции, такие как setTimeout или setInterval, можно также шпионить, чтобы тестировать их поведение. Например, можно проверить, был ли вызван таймер с нужными параметрами:

describe('Шпион для setTimeout', function () {
  it('должен отслеживать вызов setTimeout', function () {
    const spy = sinon.spy();
    const timer = setTimeout(spy, 100);

    clearTimeout(timer);

    sinon.assert.notCalled(spy);
  });
});

Модификация поведения функции

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

const spy = sinon.spy(function () {
  return 'modified';
});

console.log(spy());  // 'modified'

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

Подведение итогов

Шпионы в Mocha, используя библиотеку Sinon, предоставляют мощный инструмент для тестирования вызовов функций, проверки их аргументов и поведения. Это особенно полезно при работе с сторонними библиотеками или при тестировании функций, которые зависят от внешних факторов. Помимо стандартных функций, шпионы поддерживают работу с асинхронными задачами и временными функциями, что делает их универсальными для различных типов тестов.