Asserting a specific stub call was made with the required arguments using sinon
Asked Answered
U

2

3

Let's say you are testing a function that will call a dependency multiple times with different arguments:

var sut = {
    ImportantFunction: function(dependency){
        dependency("a", 1);
        dependency("b", 2);
    }
};

Using QUnit + Sinon and assuming the order of the calls is not important, I could write the following test that makes sure the function calls the dependency as expected:

test("dependency was called as expected", function () {
    var dependencyStub = sinon.stub();

    sut.ImportantFunction(dependencyStub);

    ok(dependencyStub.calledTwice, "dependency was called twice");            
    sinon.assert.calledWith(dependencyStub, "a", 1);
    sinon.assert.calledWith(dependencyStub, "b", 2);
});

But what if the order is important and I want the test to take it into account? What is the best way to write such a test using QUnit+Sinon?

I have used the following approach, but I am losing the descriptive failure message provided by sinon assertions (which shows expected and actual values). For this I have just manually added some descriptive message, but it is not as useful as having a failure message with the expected and actual values (and has to be manually maintained).

ok(dependencyStub.firstCall.calledWith("a", 1), "dependency called with expected args 'a', 1");
ok(dependencyStub.secondCall.calledWith("b", 2), "dependency called with expected args 'b', 2");

Is there a way of using an assertion like sinon.assert.calledWith for a particular call like the first or second call?

Sample setup in this fiddle

Unstained answered 27/4, 2015 at 15:18 Comment(0)
W
7

You can use sinon.assert.callOrder(spy1, spy2, ...), or spy1.calledBefore(spy2) or spy2.calledAfter(spy1).

These can also be used with the result of spy.calledWith(...), e.g. sinon.assert.callOrder(spy.withArgs('a'), spy.withArgs('b')).

Worldshaking answered 27/4, 2015 at 20:2 Comment(1)
Thanks, this allows nice tests too and works in older versions of Sinon :)Unstained
U
11

And just as I was creating the sample fiddle I have found the solution...

In my code I was using version 1.7.1 of Sinon, but while writing the fiddle using Sinon's latest version (1.14.1 as of today) I just realized that you can pass a particular spyCall to the assert.calledWith method. This means you can write the following:

sinon.assert.calledWith(dependencyStub.firstCall, "a", 1);
sinon.assert.calledWith(dependencyStub.secondCall, "b", 2);

So the test I wanted to create can be nicely written:

test("dependency was called multiple times as expected - with order", function () {
    var dependencyStub = sinon.stub();

    sut.ImportantFunction(dependencyStub);

    sinon.assert.calledTwice(dependencyStub);
    sinon.assert.calledWith(dependencyStub.firstCall, "a", 1);
    sinon.assert.calledWith(dependencyStub.secondCall, "b", 2);    
});

Fiddle here

Edit

Found in the github repository the discussion that introduced this change. By the date the change was merged to master, this should work on version 1.13.0 and newer.

If you are using older versions, you can use mantoni´s solution:

test("dependency was called multiple times as expected with order - pre 1.13.0", function () {
    var dependencyStub = sinon.stub();

    sut.ImportantFunction(dependencyStub);

    sinon.assert.calledTwice(dependencyStub);
    sinon.assert.callOrder(
        dependencyStub.withArgs("a", 1), 
        dependencyStub.withArgs("b", 2));
});
Unstained answered 27/4, 2015 at 15:32 Comment(0)
W
7

You can use sinon.assert.callOrder(spy1, spy2, ...), or spy1.calledBefore(spy2) or spy2.calledAfter(spy1).

These can also be used with the result of spy.calledWith(...), e.g. sinon.assert.callOrder(spy.withArgs('a'), spy.withArgs('b')).

Worldshaking answered 27/4, 2015 at 20:2 Comment(1)
Thanks, this allows nice tests too and works in older versions of Sinon :)Unstained

© 2022 - 2024 — McMap. All rights reserved.