Spec-Zone.ru › Sinon.JS 5

Заглушки

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

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

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

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

stub.returnsThis();

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

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

stub.resolves(value);

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

При создании промиса sinon использует метод Promise.resolve. Вы несете ответственность за предоставление полифилла в средах, которые не предоставляют 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();

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

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

С sinon@2.0.0

stub.rejects("TypeError");

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

С sinon@2.0.0

stub.rejects(value);

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

С 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);

Заставляет заглушку возвращать промисы, используя определенную библиотеку промисов вместо глобальной, когда используется 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/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–2018 Christian Johansen
Licensed under the BSD License.
http://sinonjs.org/releases/v5.1.0/stubs

Spec-Zone.ru

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