Sign Up

Sign Up to our social questions and Answers Engine to ask questions, answer people’s questions, and connect with other people.

Have an account? Sign In

Have an account? Sign In Now

Sign In

Login to our social questions & Answers Engine to ask questions answer people’s questions & connect with other people.

Sign Up Here

Forgot Password?

Don't have account, Sign Up Here

Forgot Password

Lost your password? Please enter your email address. You will receive a link and will create a new password via email.

Have an account? Sign In Now

You must login to ask a question.

Forgot Password?

Need An Account, Sign Up Here

Please briefly explain why you feel this question should be reported.

Please briefly explain why you feel this answer should be reported.

Please briefly explain why you feel this user should be reported.

Sign InSign Up

The Archive Base

The Archive Base Logo The Archive Base Logo

The Archive Base Navigation

  • Home
  • SEARCH
  • About Us
  • Blog
  • Contact Us
Search
Ask A Question

Mobile menu

Close
Ask a Question
  • Home
  • Add group
  • Groups page
  • Feed
  • User Profile
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Buy Points
  • Users
  • Help
  • Buy Theme
  • SEARCH
Home/ Questions/Q 8019017
In Process

The Archive Base Latest Questions

Editorial Team
  • 0
Editorial Team
Asked: June 4, 20262026-06-04T21:16:01+00:00 2026-06-04T21:16:01+00:00

In the following unit test code: TestModel = Backbone.Model.extend({ defaults: { ‘selection’: null },

  • 0

In the following unit test code:

TestModel = Backbone.Model.extend({
    defaults: {
        'selection': null
    },
    initialize: function() {
      this.on('change:selection', this.doSomething);
    },
    doSomething: function() {
        console.log("Something has been done.");
    }
});

module("Test", {
    setup: function() {
        this.testModel = new TestModel();
    }
});

test("intra-model event bindings", function() {
    this.spy(this.testModel, 'doSomething');
    ok(!this.testModel.doSomething.called);
    this.testModel.doSomething();
    ok(this.testModel.doSomething.calledOnce);
    this.testModel.set('selection','something new');
    ok(this.testModel.doSomething.calledTwice); //this test should past, but fails.  Console shows two "Something has been done" logs.
});

The third ok fails, even though the function was effectively called from the backbone event binding, as demo’d by the console.

3rd test fails
enter image description here

This is very frustrating and has shaken my confidence on whether sinon.js is suitable for testing my backbone app. Am I doing something wrong, or is this a problem with how sinon detects whether something has been called? Is there a workaround?

EDIT: Here’s a solution to my specific example, based on the monkey patch method of the accepted answer. While its a few lines of extra setup code in the test itself, (I don’t need the module function any more) it gets the job done. Thanks, mu is too short

test("intra-model event bindings", function() {
    var that = this;
    var init = TestModel.prototype.initialize;
    TestModel.prototype.initialize = function() {
        that.spy(this, 'doSomething');
        init.call(this);
    };

    this.testModel = new TestModel();
    . . . // tests pass!
}); 
  • 1 1 Answer
  • 0 Views
  • 0 Followers
  • 0
Share
  • Facebook
  • Report

Leave an answer
Cancel reply

You must login to add an answer.

Forgot Password?

Need An Account, Sign Up Here

1 Answer

  • Voted
  • Oldest
  • Recent
  • Random
  1. Editorial Team
    Editorial Team
    2026-06-04T21:16:02+00:00Added an answer on June 4, 2026 at 9:16 pm

    Calling this.spy(this.testModel, 'doSomething') replaces the testModel.doSomething method with a new wrapper method:

    var spy = sinon.spy(object, “method”);

    Creates a spy for object.method and replaces the original method with the spy.

    So this.spy(this.testModel, 'doSomething') is effectively doing something like this:

    var m = this.testModel.doSomething;
    this.testModel.doSomething = function() {
        // Spying stuff goes here...
        return m.apply(this, arguments);
    };
    

    This means that testModel.doSomething is a different function when you bind the event handler in initialize:

    this.bind('change:selection', this.doSomething);
    

    than it is after you’ve attached your spying. The Backbone event dispatcher will call the original doSomething method but that one doesn’t have the Sinon instrumentation. When you call doSomething manually, you’re calling the new function that spy added and that one does have the Sinon instrumentation.

    If you want to use Sinon to test your Backbone events, then you’ll have to arrange to have the Sinon spy call applied to the model before you bind any event handlers and that probably means hooking into initialize.

    Maybe you could monkey-patch your model’s initialize to add the necessary spy calls before it binds any event handlers:

    var init = Model.prototype.initialize;
    Model.prototype.initialize = function() {
        // Set up the Spy stuff...
        init.apply(this, arguments);
    };
    

    Demo: http://jsfiddle.net/ambiguous/C4fnX/1/

    You could also try subclassing your model with something like:

    var Model = Backbone.Model.extend({});
    var TestModel = Model.extend({
        initialize: function() {
            // Set up the Spy stuff...
            Model.prototype.initialize.apply(this, arguments);
        }
    });
    

    And then use TestModel instead of Model, this would give you an instrumented version of Model in TestModel without having to include a bunch of test-specific code inside your normal production-ready Model. The downside is that anything else that uses Model would need to be subclassed/patched/… to use TestModel instead.

    Demo: http://jsfiddle.net/ambiguous/yH3FE/1/

    You might be able to get around the TestModel problem with:

    var OriginalModel = Model;
    Model = Model.extend({
        initialize: function() {
            // Set up the Spy stuff...
            OriginalModel.prototype.initialize.apply(this, arguments);
        }
    });
    

    but you’d have to get the ordering right to make sure that everyone used the new Model rather than the old one.

    Demo: http://jsfiddle.net/ambiguous/u3vgF/1/

    • 0
    • Reply
    • Share
      Share
      • Share on Facebook
      • Share on Twitter
      • Share on LinkedIn
      • Share on WhatsApp
      • Report

Sidebar

Related Questions

I'd like to unit-test the following function with NUnit and Rhino Mocks. The function
How can I convert the following code to use boost unit test framework: #include
I wrote a unit test for my code. The code looks like the following:
The last Unit Test of in the following code fails, probably because the ==
I have a unit test which contains the following line of code Site.objects.get(name=UnitTest).delete() and
I have the following NancyFX unit test. I use the Shouldly assertion library to
I have the following as my unit test: void testCreateDealer() { mockForConstraintsTests(Dealer) def _dealer=
My unit test keeps getting the following error: System.InvalidOperationException: The Connection is not open.
Following on from this question...I'm trying to unit test the following scenario: I have
I am trying to write a unit test for the following class: @Transactional public

Explore

  • Home
  • Add group
  • Groups page
  • Communities
  • Questions
    • New Questions
    • Trending Questions
    • Must read Questions
    • Hot Questions
  • Polls
  • Tags
  • Badges
  • Users
  • Help
  • SEARCH

Footer

© 2021 The Archive Base. All Rights Reserved
With Love by The Archive Base

Insert/edit link

Enter the destination URL

Or link to existing content

    No search term specified. Showing recent items. Search or use up and down arrow keys to select an item.