Spec-Zone.ru › Sinon.JS 4

Заглушки

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

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

Они поддерживают полный 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 заглушек

Если вам нужно создать заглушку для геттеров/сеттеров или свойств, не являющихся функциями, следует использовать sandbox.stub

Свойства

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)

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

stub.resetBehavior();

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

var stub = sinon.stub();

stub.returns(54)

stub(); // 54

stub.resetBehavior();

stub(); // undefined

stub.resetHistory();

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

var stub = sinon.stub();

stub.called // false

stub();

stub.called // true

stub.resetHistory();

stub.called // false

С sinon@2.0.0

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); заставляет заглушку возвращать первый аргумент.

stub.returnsThis();

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

Полезно для заглушения jQuery-подобных API.

stub.resolves(value);

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

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

С sinon@2.0.0

stub.throws();

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

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

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

stub.throws(obj);

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

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

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

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); заставляет заглушку вызвать первый аргумент как колбэк.

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.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.

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

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

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

Как выше, но с дополнительным параметром для передачи контекста 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/ru/docs/guides/event-loop-timers-and-nexttick,
  • https://developer.mozilla.org/ru/docs/Web/JavaScript/EventLoop,
  • https://developer.mozilla.org/ru/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–2018 Christian Johansen
Licensed under the BSD License.
http://sinonjs.org/releases/v4.5.0/stubs

Spec-Zone.ru

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