QUnit,Sinon.js&骨干单元测试受挫:sinon间谍似乎未能检测到Backbone Model事件回调

时间:2012-06-02 19:39:22

标签: javascript backbone.js qunit sinon

在以下单元测试代码中:

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

第三个ok失败,即使该函数是从主干事件绑定中有效调用的,如控制台演示的那样。

3rd test fails enter image description here

这非常令人沮丧,并且让我对sinon.js是否适合测试我的骨干应用程序感到震惊。我做错了什么,或者这是一个问题,sinon如何检测是否已经调用了某些东西?有解决方法吗?

编辑:这是我的具体示例的解决方案,基于接受答案的猴子补丁方法。虽然它在测试中有几行额外的设置代码,(我不再需要模块功能)但它完成了工作。谢谢,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 个答案:

答案 0 :(得分:12)

致电this.spy(this.testModel, 'doSomething')testModel.doSomething方法替换为new wrapper method

  

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

     

object.method创建一个间谍,并用间谍替换原始方法。

所以this.spy(this.testModel, 'doSomething')实际上是这样做的:

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

这意味着在testModel.doSomething中绑定事件处理程序时initialize是一个不同的函数:

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

在你附加间谍之后。 Backbone事件调度程序将调用原始doSomething方法,但该方法没有Sinon检测。当您手动调用doSomething时,您正在调用spy添加的新函数,并且该函数具有Sinon检测。

如果你想使用Sinon测试你的Backbone事件,那么你必须安排在绑定任何事件处理程序之前将Sinon spy调用应用于模型,这可能意味着挂钩{{ 1}}。

也许你可以修补模型的initialize,以便在绑定任何事件处理程序之前添加必要的initialize调用:

spy

演示:http://jsfiddle.net/ambiguous/C4fnX/1/

您还可以尝试使用以下内容对模型进行子类化:

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

然后使用var Model = Backbone.Model.extend({}); var TestModel = Model.extend({ initialize: function() { // Set up the Spy stuff... Model.prototype.initialize.apply(this, arguments); } }); 代替模型,这将在TestModel中为您提供Model的检测版本,而无需在正常生产中包含一堆特定于测试的代码 - 准备好TestModel。缺点是使用Model的任何其他内容都需要进行子类化/修补/ ...以使用Model代替。

演示:http://jsfiddle.net/ambiguous/yH3FE/1/

您可以通过以下方式解决TestModel问题:

TestModel

但你必须得到正确的订购,以确保每个人都使用新的var OriginalModel = Model; Model = Model.extend({ initialize: function() { // Set up the Spy stuff... OriginalModel.prototype.initialize.apply(this, arguments); } }); 而不是旧的。{/ p>

演示:http://jsfiddle.net/ambiguous/u3vgF/1/