W3cubDocs

/Sinon.JS 7

Stubs

What are stubs?

Test stubs are functions (spies) with pre-programmed behavior.

They support the full test spy API in addition to methods which can be used to alter the stub’s behavior.

As spies, stubs can be either anonymous, or wrap existing functions. When wrapping an existing function with a stub, the original function is not called.

When to use stubs?

Use a stub when you want to:

  1. Control a method’s behavior from a test to force the code down a specific path. Examples include forcing a method to throw an error in order to test error handling.

  2. When you want to prevent a specific method from being called directly (possibly because it triggers undesired behavior, such as a XMLHttpRequest or similar).

The following example is yet another test from PubSubJS which shows how to create an anonymous stub that throws an exception when called.

"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));
}

Note how the stub also implements the spy interface. The test verifies that all callbacks were called, and also that the exception throwing stub was called before one of the other callbacks.

Defining stub behavior on consecutive calls

Calling behavior defining methods like returns or throws multiple times overrides the behavior of the stub. As of Sinon version 1.8, you can use the onCall method to make a stub respond differently on consecutive calls.

Note that in Sinon version 1.5 to version 1.7, multiple calls to the yields* and callsArg* family of methods define a sequence of behaviors for consecutive calls. As of 1.8, this functionality has been removed in favor of the onCall API.

Stub API

Properties

var stub = sinon.stub();

Creates an anonymous stub function

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

Replaces object.method with a stub function. An exception is thrown if the property is not already a function.

The original function can be restored by calling object.method.restore(); (or stub.restore();).

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

This has been removed from v3.0.0. Instead you should use

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

A codemod is available to upgrade your code

var stub = sinon.stub(obj);

Stubs all the object’s methods.

Note that it’s usually better practice to stub individual methods, particularly on objects that you don’t understand or control all the methods for (e.g. library dependencies).

Stubbing individual methods tests intent more precisely and is less susceptible to unexpected behavior as the object’s code evolves.

If you want to create a stub object of MyConstructor, but don’t want the constructor to be invoked, use this utility function.

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

overrides is an optional map overriding created stubs, for example:

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

is the same as:

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

If provided value is not a stub, it will be used as the returned value:

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

is the same as:

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

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

Stubs the method only for the provided arguments.

This is useful to be more expressive in your assertions, where you can access the spy with the same call. It is also useful to create a stub that can act differently in response to different arguments.

"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); Added in v1.8

Defines the behavior of the stub on the nth call. Useful for testing sequential interactions.

"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
}

There are methods onFirstCall, onSecondCall,onThirdCall to make stub definitions read more naturally.

onCall can be combined with all of the behavior defining methods in this section. In particular, it can be used together with 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
}

Note how the behavior of the stub for argument 42 falls back to the default behavior once no more calls have been defined.

stub.onFirstCall();

Alias for stub.onCall(0);

stub.onSecondCall();

Alias for stub.onCall(1);

stub.onThirdCall();

Alias for stub.onCall(2);

stub.reset();

Resets both behaviour and history of the stub.

This is equivalent to calling both stub.resetBehavior() and stub.resetHistory()

Updated in [email protected]

Since [email protected]

As a convenience, you can apply stub.reset() to all stubs using sinon.reset()

stub.resetBehavior();

Resets the stub’s behaviour to the default behaviour

var stub = sinon.stub();

stub.returns(54)

stub(); // 54

stub.resetBehavior();

stub(); // undefined

Since [email protected]

You can reset behaviour of all stubs using sinon.resetBehavior()

stub.resetHistory();

Since [email protected]

Resets the stub’s history

var stub = sinon.stub();

stub.called // false

stub();

stub.called // true

stub.resetHistory();

stub.called // false

Since [email protected]

You can reset history of all stubs using sinon.resetHistory()

stub.callsFake(fakeFunction);

Makes the stub call the provided fakeFunction when invoked.

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

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

myObj.prop(); // 'bar'

stub.returns(obj);

Makes the stub return the provided value.

stub.returnsArg(index);

Causes the stub to return the argument at the provided index.

stub.returnsArg(0); causes the stub to return the first argument.

If the argument at the provided index is not available, prior to [email protected], an undefined value will be returned; starting from [email protected], a TypeError will be thrown.

stub.returnsThis();

Causes the stub to return its this value.

Useful for stubbing jQuery-style fluent APIs.

stub.resolves(value);

Causes the stub to return a Promise which resolves to the provided value.

When constructing the Promise, sinon uses the Promise.resolve method. You are responsible for providing a polyfill in environments which do not provide Promise. The Promise library can be overwritten using the usingPromise method.

Since [email protected]

stub.resolvesArg(index);

Causes the stub to return a Promise which resolves to the argument at the provided index.

stub.resolvesArg(0); causes the stub to return a Promise which resolves to the first argument.

If the argument at the provided index is not available, a TypeError will be thrown.

Since [email protected]

stub.throws();

Causes the stub to throw an exception (Error).

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

Causes the stub to throw an exception with the name property set to the provided string. The message parameter is optional and will set the message property of the exception.

stub.throws(obj);

Causes the stub to throw the provided exception object.

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

Causes the stub to throw the exception returned by the function.

stub.throwsArg(index);

Causes the stub to throw the argument at the provided index.

stub.throwsArg(0); causes the stub to throw the first argument as the exception.

If the argument at the provided index is not available, a TypeError will be thrown.

Since [email protected]

stub.rejects();

Causes the stub to return a Promise which rejects with an exception (Error).

When constructing the Promise, sinon uses the Promise.reject method. You are responsible for providing a polyfill in environments which do not provide Promise. The Promise library can be overwritten using the usingPromise method.

Since [email protected]

stub.rejects("TypeError");

Causes the stub to return a Promise which rejects with an exception of the provided type.

Since [email protected]

stub.rejects(value);

Causes the stub to return a Promise which rejects with the provided exception object.

Since [email protected]

stub.callsArg(index);

Causes the stub to call the argument at the provided index as a callback function.

stub.callsArg(0); causes the stub to call the first argument as a callback.

If the argument at the provided index is not available or is not a function, a TypeError will be thrown.

stub.callThrough();

Causes the original method wrapped into the stub to be called when none of the conditional stubs are matched.

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

Like stub.callsArg(index); but with an additional parameter to pass the this context.

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

Like callsArg, but with arguments to pass to the callback.

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

Like above but with an additional parameter to pass the this context.

stub.usingPromise(promiseLibrary);

Causes the stub to return promises using a specific Promise library instead of the global one when using stub.rejects or stub.resolves. Returns the stub to allow chaining.

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

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

Since [email protected]

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

Similar to callsArg.

Causes the stub to call the first callback it receives with the provided arguments (if any).

If a method accepts more than one callback, you need to use yieldsRight to call the last callback or callsArg to have the stub invoke other callbacks than the first or last one.

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

Like yields but calls the last callback it receives.

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

Like yields but with an additional parameter to pass the this context.

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

Causes the spy to invoke a callback passed as a property of an object to the spy.

Like yields, yieldsTo grabs the first matching argument, finds the callback and calls it with the (optional) arguments.

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

Like above but with an additional parameter to pass the this context.

"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, ...])

Invoke callbacks passed to the stub with the given arguments.

If the stub was never called with a function argument, yield throws an error.

Returns an Array with all callbacks return values in the order they were called, if no error is thrown.

Also aliased as invokeCallback.

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

Invokes callbacks passed as a property of an object to the stub.

Like yield, yieldTo grabs the first matching argument, finds the callback and calls it with the (optional) arguments.

"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)

Like yield, but with an explicit argument number specifying which callback to call.

Useful if a function is called with more than one callback, and simply calling the first callback is not desired.

"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, ...])

Like callArg, but with arguments.

Asynchronous calls

Same as their corresponding non-Async counterparts, but with callback being deferred at called after all instructions in the current call stack are processed.

  • In Node environment the callback is deferred with process.nextTick.
  • In a browser the callback is deferred with setTimeout(callback, 0).

More information:

stub.callsArgAsync(index);

Async version of stub.callsArg(index). See also Asynchronous calls.

stub.callsArgOnAsync(index, context);

Async version of stub.callsArgOn(index, context). See also Asynchronous calls.

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

Async version of stub.callsArgWith(index, arg1, arg2, …). See also Asynchronous calls.

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

Async version of stub.callsArgOnWith(index, context, arg1, arg2, …). See also Asynchronous calls.

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

Async version of stub.yields([arg1, arg2, …]). See also Asynchronous calls.

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

Async version of stub.yieldsOn(context, [arg1, arg2, …]). See also Asynchronous calls.

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

Async version of stub.yieldsTo(property, [arg1, arg2, …]). See also Asynchronous calls.

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

Async version of stub.yieldsToOn(property, context, [arg1, arg2, …]). See also Asynchronous calls.

sinon.addBehavior(name, fn);

Add a custom behavior. The name will be available as a function on stubs, and the chaining mechanism will be set up for you (e.g. no need to return anything from your function, its return value will be ignored). The fn will be passed the fake instance as its first argument, and then the user’s arguments.

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)

Replaces a new getter for this stub.

var myObj = {
    prop: 'foo'
};

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

myObj.prop; // 'bar'

stub.set(setterFn)

Defines a new setter for this stub.

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)

Defines a new value for this stub.

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

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

myObj.example; // 'newValue'

You can restore values by calling the restore method:

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.
https://sinonjs.org/releases/v7.1.1/stubs