In the following unit test code:
TestModel = Backbone.Model.extend({
defaults: {
\'selection\': null
},
initialize: function() {
th
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/