Spec-Zone.ru › Sinon.JS 8

Заглушки

Что такое заглушки?

Тестовые заглушки — это функции (шпионы) с запрограммированным поведением.

Они поддерживают полный API шпионских тестов, помимо методов, которые могут использоваться для изменения поведения заглушки.

В качестве шпионов заглушки могут быть анонимными или обертывать существующие функции. При обертывании существующей функции заглушкой оригинальная функция не вызывается.

Когда использовать заглушки?

Используйте заглушку, когда хотите:

  1. Управлять поведением метода из теста, чтобы принудительно заставить код следовать определённому пути. Примеры включают принуждение метода к выбросу ошибки для проверки обработки ошибок.

  2. Когда хотите предотвратить прямой вызов определённого метода (возможно, потому что это вызывает нежелательное поведение, например, XMLHttpRequest или подобное).

Следующий пример — ещё один тест из PubSubJS, который демонстрирует, как создать анонимную заглушку, выбрасывающую исключение при вызове.

"test should call all subscribers, even if there are exceptions" : function(){
    var message = 'an example message';
    var stub = sinon.stub().throws();
    var spy1 = sinon.spy();
    var spy2 = sinon.spy();

    PubSub.subscribe(message, stub);
    PubSub.subscribe(message, spy1);
    PubSub.subscribe(message, spy2);

    PubSub.publishSync(message, undefined);

    assert(spy1.called);
    assert(spy2.called);
    assert(stub.calledBefore(spy1));
}

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

Определение поведения заглушки при последовательных вызовах

Вызов методов определения поведения, таких как returns или throws, несколько раз перезаписывает поведение заглушки. Начиная с версии Sinon 1.8, вы можете использовать метод onCall, чтобы заглушка реагировала по-разному при последовательных вызовах.

Обратите внимание, что в версиях Sinon от 1.5 до 1.7 несколько вызовов семейства методов yields* и callsArg* определяют последовательность поведения для последовательных вызовов. Начиная с версии 1.8, эта функциональность была удалена в пользу API onCall.

API заглушки

Свойства

var stub = sinon.stub();

Создаёт анонимную функцию-заглушку

var stub = sinon.stub(object, "method");

Заменяет object.method на функцию-заглушку. Если свойство не является функцией, выбрасывается исключение.

Исходную функцию можно восстановить, вызвав object.method.restore(); (или stub.restore();).

var stub = sinon.stub(object, "method", func);

Это было удалено из v3.0.0. Вместо этого вы должны использовать

stub(obj, 'meth').callsFake(fn)

Доступен кодмод для обновления вашего кода

var stub = sinon.stub(obj);

Заглушает все методы объекта.

Обратите внимание, что обычно лучше заглушать отдельные методы, особенно для объектов, которые вы не понимаете или не контролируете все методы (например, зависимости библиотек).

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

Если вы хотите создать объект-заглушку для MyConstructor, но не хотите вызывать конструктор, используйте эту служебную функцию.

var stub = sinon.createStubInstance(MyConstructor, overrides);

overrides — это необязательная карта, переопределяющая созданные заглушки, например:

var stub = sinon.createStubInstance(MyConstructor, {
    foo: sinon.stub().returnsThis()
});

это то же самое, что:

var stub = sinon.createStubInstance(MyConstructor);
stub.foo.returnsThis();

Если предоставленное значение не является заглушкой, оно будет использовано в качестве возвращаемого значения:

var stub = sinon.createStubInstance(MyConstructor, {
    foo: 3
});

это то же самое, что:

var stub = sinon.createStubInstance(MyConstructor);
stub.foo.returns(3);

stub.withArgs(arg1[, arg2, ...]);

Заглушает метод только для указанных аргументов.

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

"test should stub method differently based on arguments": function () {
    var callback = sinon.stub();
    callback.withArgs(42).returns(1);
    callback.withArgs(1).throws("name");

    callback(); // No return value, no exception
    callback(42); // Returns 1
    callback(1); // Throws Error("name")
}

stub.onCall(n); Добавлен в v1.8

Определяет поведение заглушки при n-ом вызове. Полезно для тестирования последовательных взаимодействий.

"test should stub method differently on consecutive calls": function () {
    var callback = sinon.stub();
    callback.onCall(0).returns(1);
    callback.onCall(1).returns(2);
    callback.returns(3);

    callback(); // Returns 1
    callback(); // Returns 2
    callback(); // All following calls return 3
}

Существуют методы onFirstCall, onSecondCall, onThirdCall, чтобы определения заглушек читались более естественно.

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

"test should stub method differently on consecutive calls with certain argument": function () {
    var callback = sinon.stub();
    callback.withArgs(42)
        .onFirstCall().returns(1)
        .onSecondCall().returns(2);
    callback.returns(0);

    callback(1); // Returns 0
    callback(42); // Returns 1
    callback(1); // Returns 0
    callback(42); // Returns 2
    callback(1); // Returns 0
    callback(42); // Returns 0
}

Обратите внимание, как поведение заглушки для аргумента 42 возвращается к стандартному поведению, когда больше не определено вызовов.

stub.onFirstCall();

Псевдоним для stub.onCall(0);

stub.onSecondCall();

Псевдоним для stub.onCall(1);

stub.onThirdCall();

Псевдоним для stub.onCall(2);

stub.reset();

Сбрасывает поведение и историю заглушки.

Это эквивалентно вызову stub.resetBehavior() и stub.resetHistory().

Обновлено в sinon@2.0.0

С sinon@5.0.0

Для удобства вы можете применить stub.reset() ко всем заглушкам, используя sinon.reset()

stub.resetBehavior();

Сбрасывает поведение заглушки до стандартного.

var stub = sinon.stub();

stub.returns(54)

stub(); // 54

stub.resetBehavior();

stub(); // undefined

С sinon@5.0.0

Вы можете сбросить поведение всех заглушек, используя sinon.resetBehavior()

stub.resetHistory();

С sinon@2.0.0

Сбрасывает историю заглушки.

var stub = sinon.stub();

stub.called // false

stub();

stub.called // true

stub.resetHistory();

stub.called // false

С sinon@5.0.0

Вы можете сбросить историю всех заглушек, используя sinon.resetHistory()

stub.callsFake(fakeFunction);

Заставляет заглушку вызывать предоставленную fakeFunction при вызове.

var myObj = {};
myObj.prop = function propFn() {
    return 'foo';
};

sinon.stub(myObj, 'prop').callsFake(function fakeFn() {
    return 'bar';
});

myObj.prop(); // 'bar'

stub.returns(obj);

Заставляет заглушку возвращать предоставленное значение.

stub.returnsArg(index);

Заставляет заглушку возвращать аргумент по указанному индексу.

stub.returnsArg(0); заставляет заглушку возвращать первый аргумент.

Если аргумент по указанному индексу недоступен, до sinon@6.1.2, будет возвращено значение undefined; начиная с sinon@6.1.2, будет выброшено исключение TypeError.

stub.returnsThis();

Заставляет заглушку возвращать своё значение this.

Полезно для заглушения jQuery-стильных API с fluent-интерфейсом.

stub.resolves(value);

Заставляет заглушку возвращать Promise, который разрешается до предоставленного значения.

При построении Promise, sinon использует метод Promise.resolve. Вы несете ответственность за предоставление полифилла в средах, которые не поддерживают Promise. Библиотеку Promise можно переопределить, используя метод usingPromise.

С sinon@2.0.0

stub.resolvesArg(index);

Заставляет заглушку возвращать Promise, который разрешается до аргумента по указанному индексу.

stub.resolvesArg(0); заставляет заглушку возвращать Promise, который разрешается до первого аргумента.

Если аргумент по указанному индексу недоступен, будет выброшено исключение TypeError.

С sinon@6.1.1

stub.throws();

Заставляет заглушку выбросить исключение (Error).

stub.throws("name"[, "optional message"]);

Заставляет заглушку выбросить исключение с свойством name установленным на предоставленную строку. Параметр message необязателен и установит свойство message исключения.

stub.throws(obj);

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

stub.throws(function() { return new Error(); });

Заставляет заглушку выбросить исключение, возвращённое функцией.

stub.throwsArg(index);

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

stub.throwsArg(0); заставляет заглушку выбросить первый аргумент как исключение.

Если аргумент по указанному индексу недоступен, будет выброшено исключение TypeError.

С sinon@2.3.0

stub.rejects();

Заставляет заглушку возвращать Promise, который отклоняется с исключением (Error).

При построении Promise, sinon использует метод Promise.reject. Вы несете ответственность за предоставление полифилла в средах, которые не поддерживают Promise. Библиотеку Promise можно переопределить, используя метод usingPromise.

С sinon@2.0.0

stub.rejects("TypeError");

Заставляет заглушку возвращать Promise, который отклоняется с исключением указанного типа.

С sinon@2.0.0

stub.rejects(value);

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

С sinon@2.0.0

stub.callsArg(index);

Заставляет заглушку вызвать аргумент по указанному индексу как обратный вызов.

stub.callsArg(0); заставляет заглушку вызвать первый аргумент как обратный вызов.

Если аргумент по указанному индексу недоступен или не является функцией, будет выброшено исключение TypeError.

stub.callThrough();

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

var stub = sinon.stub();

var obj = {};

obj.sum = function sum(a, b) {
    return a + b;
};

stub(obj, 'sum');

obj.sum.withArgs(2, 2).callsFake(function foo() {
    return 'bar';
});

obj.sum.callThrough();

obj.sum(2, 2); // 'bar'
obj.sum(1, 2); // 3

stub.callThroughWithNew();

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

var obj = {};

obj.Sum = function MyConstructor(a, b) {
    this.result = a + b;
};

sinon
    .stub(obj, 'Sum')
    .callThroughWithNew()
    .withArgs(1, 2)
    .returns({ result: 9000 });

(new obj.Sum(2, 2)).result;  // 4
(new obj.Sum(1, 2)).result;  // 9000

stub.callsArgOn(index, context);

Подобно stub.callsArg(index);, но с дополнительным параметром для передачи контекста this.

stub.callsArgWith(index, arg1, arg2, ...);

Подобно callsArg, но с аргументами для передачи в обратный вызов.

stub.callsArgOnWith(index, context, arg1, arg2, ...);

Подобно вышесказанному, но с дополнительным параметром для передачи контекста this.

stub.usingPromise(promiseLibrary);

Заставляет заглушку возвращать promises, используя определённую библиотеку Promise вместо глобальной, когда используется stub.rejects или stub.resolves. Возвращает заглушку для возможности цепочки.

var myObj = {
    saveSomething: sinon.stub().usingPromise(bluebird.Promise).resolves("baz");
}

myObj.saveSomething()
    .tap(function(actual) {
        console.log(actual); // baz
    });

С sinon@2.0.0

stub.yields([arg1, arg2, ...])

Аналогично callsArg.

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

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

stub.yieldsRight([arg1, arg2, ...])

Подобно yields, но вызывает последний полученный обратный вызов.

stub.yieldsOn(context, [arg1, arg2, ...])

Подобно yields, но с дополнительным параметром для передачи контекста this.

stub.yieldsTo(property, [arg1, arg2, ...])

Заставляет шпион вызвать обратный вызов, переданный как свойство объекта шпиону.

Подобно yields, yieldsTo получает первый соответствующий аргумент, находит обратный вызов и вызывает его с (необязательными) аргументами.

stub.yieldsToOn(property, context, [arg1, arg2, ...])

Подобно вышесказанному, но с дополнительным параметром для передачи контекста this.

"test should fake successful ajax request": function () {
    sinon.stub(jQuery, "ajax").yieldsTo("success", [1, 2, 3]);

    jQuery.ajax({
        success: function (data) {
            assertEquals([1, 2, 3], data);
        }
    });
}

stub.yield([arg1, arg2, ...])

Вызов колбэков, переданных в stub, с заданными аргументами.

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

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

Также алиасируется как invokeCallback.

stub.yieldTo(callback, [arg1, arg2, ...])

Вызов колбэков, переданных как свойство объекта, заглушке.

Как и yield, yieldTo захватывает первый соответствующий аргумент, находит колбэк и вызывает его с (необязательными) аргументами.

"calling callbacks": function () {
    var callback = sinon.stub();
    callback({
        "success": function () {
            console.log("Success!");
        },
        "failure": function () {
            console.log("Oh noes!");
        }
    });

    callback.yieldTo("failure"); // Logs "Oh noes!"
}

stub.callArg(argNum)

Как yield, но с явным номером аргумента, определяющим, какой колбэк вызывать.

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

"calling the last callback": function () {
    var callback = sinon.stub();
    callback(function () {
        console.log("Success!");
    }, function () {
        console.log("Oh noes!");
    });

    callback.callArg(1); // Logs "Oh noes!"
}

stub.callArgWith(argNum, [arg1, arg2, ...])

Как callArg, но с аргументами.

Асинхронные вызовы

То же самое, что и их соответствующие не-асинхронные аналоги, но с отложенным колбэком, который вызывается после обработки всех инструкций в текущей стеке вызовов.

  • В среде Node колбэк откладывается с помощью process.nextTick.
  • В браузере колбэк откладывается с помощью setTimeout(callback, 0).

Дополнительная информация:

  • https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick,
  • https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop,
  • https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout.
stub.callsArgAsync(index);

Асинхронная версия stub.callsArg(index). См. также Асинхронные вызовы.

stub.callsArgOnAsync(index, context);

Асинхронная версия stub.callsArgOn(index, context). См. также Асинхронные вызовы.

stub.callsArgWithAsync(index, arg1, arg2, ...);

Асинхронная версия stub.callsArgWith(index, arg1, arg2, …). См. также Асинхронные вызовы.

stub.callsArgOnWithAsync(index, context, arg1, arg2, ...);

Асинхронная версия stub.callsArgOnWith(index, context, arg1, arg2, …). См. также Асинхронные вызовы.

stub.yieldsAsync([arg1, arg2, ...]);

Асинхронная версия stub.yields([arg1, arg2, …]). См. также Асинхронные вызовы.

stub.yieldsOnAsync(context, [arg1, arg2, ...]);

Асинхронная версия stub.yieldsOn(context, [arg1, arg2, …]). См. также Асинхронные вызовы.

stub.yieldsToAsync(property, [arg1, arg2, ...]);

Асинхронная версия stub.yieldsTo(property, [arg1, arg2, …]). См. также Асинхронные вызовы.

stub.yieldsToOnAsync(property, context, [arg1, arg2, ...])

Асинхронная версия stub.yieldsToOn(property, context, [arg1, arg2, …]). См. также Асинхронные вызовы.

sinon.addBehavior(name, fn);

Добавление пользовательского поведения. Название будет доступно в виде функции для заглушек, и механизм цепочки вызовов будет настроен за вас (например, вам не нужно возвращать что-либо из вашей функции, её значение возврата будет проигнорировано). fn получит фейковый экземпляр в качестве первого аргумента, а затем аргументы пользователя.

const sinon = require('sinon');

sinon.addBehavior('returnsNum', (fake, n) => fake.returns(n));

var stub = sinon.stub().returnsNum(42);

assert.equals(stub(), 42);

stub.get(getterFn)

Заменяет новый геттер для этой заглушки.

var myObj = {
    prop: 'foo'
};

sinon.stub(myObj, 'prop').get(function getterFn() {
    return 'bar';
});

myObj.prop; // 'bar'

stub.set(setterFn)

Определяет новый сеттер для этой заглушки.

var myObj = {
    example: 'oldValue',
    prop: 'foo'
};

sinon.stub(myObj, 'prop').set(function setterFn(val) {
    myObj.example = val;
});

myObj.prop = 'baz';

myObj.example; // 'baz'

stub.value(newVal)

Определяет новое значение для этой заглушки.

var myObj = {
    example: 'oldValue',
};

sinon.stub(myObj, 'example').value('newValue');

myObj.example; // 'newValue'

Вы можете восстановить значения, вызвав метод restore.

var myObj = {
    example: 'oldValue',
};

var stub = sinon.stub(myObj, 'example').value('newValue');
stub.restore()

myObj.example; // 'oldValue'

© 2010–2020 Christian Johansen
Licensed under the BSD License.
https://sinonjs.org/releases/v8.1.1/stubs

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API