Skip to content

Instantly share code, notes, and snippets.

@ldong
Last active August 29, 2015 14:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ldong/3ecd55ff5ef977d2cd18 to your computer and use it in GitHub Desktop.
Save ldong/3ecd55ff5ef977d2cd18 to your computer and use it in GitHub Desktop.
javascript testing library - SinonJS

JavaScript

Sinon

What is Sinon? It is a unit test library for JavaScript.

It has 5 parts:

  1. Spy: The Test Spy is designed to act as an observation point by recording the method calls made to it by the SUT as it is exercised.

  2. Stub: The Test Stub replaces a real object with a test-specific object that feeds the desired indirect inputs into the system under test. Stubs do not proxy original methods. Stubs have an API for controlling behavior.

  3. Mock: The mock replaces an object the system under test (SUT) depends on with a test-specific object that verifies it is being used correctly by the SUT. State expectations up-front. No need for assertions. Mocks are spies and stubs.

  4. Fake Timers.

  5. Fake Servers: Declare responses upfront "Unknown" requests get a 404 Process async requests with server.respond()

Spy

“A test spy is a function that records arguments, return value, the value of this and exception thrown (if any) for all its calls. A test spy can be an anonymous function or it can wrap an existing function.”

Features: called, callCount, calledWith, threw, returned.

  1. Create a spy function

    var callback = sinon.spy();
    
    callback(); // Invoke the spy callback function
    
    callback.called;
    callback.callCount;
    callback.calledWith(arg1);
    callback.threw();
    callback.returned(obj);
    callback.calledBefore(spy);
    callback.calledAfter(spy);
  2. Turn an existing function into a spy function

    sinon.spy($, "ajax");
    
    $.ajax({ / ... / }); // Call spy version of jQuery.ajax
    
    var call = $.ajax.getCall(0);
    
    call.args;
    call.exception;
    call.returnValue;
    
    $.ajax.restore();

Stub

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

Example

var stub = sinon.stub(),
    opts = { call: function (msg) { console.log(msg); } };

// We can control how the sinon.stub() will behave based on how it’s called!
stub.withArgs("Hello").returns("World");
stub.withArgs("Wuz").returns("Zup?");
stub.withArgs("Kapow").throws();
stub.withArgs(opts).yieldsTo("call", ["Howdy"]);

stub("Hello"); // "World"
stub(opts); // "Howdy"


// notes, all above stub.withArgs(opts) can be replaced
// with stub.yieldsTo(property, [arg1, arg2, ...])

Another example mockServer.coffee uses ajax, yieldsTo

Mock

“Mocks (and mock expectations) are fake methods (like spies) with pre-programmed behavior (like stubs) as well as pre-programmed expectations. A mock will fail your test if it is not used as expected.”

i.e.

var opts = { call: function (msg) { console.log(msg); } },
    mock = sinon.mock(opts);

// You state your success criteria upfront
mock.expects("call").once().withExactArgs("Hello World");
/* ... twice, atMost, never, exactly, on, etc ... */

opts.call("Hello World");

mock.verify();

mock.restore();

Fake Timers

"Fake timers is a synchronous implementation of setTimeout and friends that Sinon.JS can overwrite the global functions with to allow you to more easily test code using them."

Example:

var clock = sinon.useFakeTimers();

var hidden =
    $("<div hidden="">Peekaboo</div>")
        .appendTo(document.body).fadeIn("slow");

clock.tick(650); // slow = 600ms
hidden.css("opacity") === 1; // true

clock.restore();

clock.tick(650) will set our time 650 ms ahead, thus hidden.css("opacity") will be true.

Fake Servers

“High-level API to manipulate FakeXMLHttpRequest instances.”

var server = sinon.fakeServer.create();

server.respondWith("GET", "/twitter/api/user.json", [
    200,
    {"Content-Type": "application/json"},
    '[{"id": 0, "tweet": "Hello World"}]'
]);

$.get("/twitter/api/user.json", function (data) {
    console.log(data); // [{"id":0,"tweet":"Hello World"}]
});
server.respond();

server.restore();

Note

So, what is the difference between using Fake Servers or just stub on the ajax call? To me, you could use either. Use Fake Servers if you want to test it on the system level rather than function levels. There you have it, how to use Sinon.JS.

Reference

[Sinon official docs] (http://sinonjs.org/docs/)

[Unit Test like a Secret Agent with Sinon.js] (http://www.elijahmanor.com/unit-test-like-a-secret-agent-with-sinon-js/)

[Sinon - Simplifying JavaScript testing] (http://cjohansen.no/talks/2011/xp-meetup/#1)

[JavaScript Test Spies, Stubs and Mocks] (http://cjohansen.no/en/javascript/javascript_test_spies_stubs_and_mocks)

[Design Goals] (http://cjohansen.no/talks/2011/xp-meetup/#6)

[一款颇具特色的前端单元测试工具——Sinon.js] (http://www.36ria.com/6194)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment