QUnit,Sinon.js和骨干单元测试无奈:兴农间谍似乎无法检测到骨干模型事件回调(QUnit,

2019-06-25 03:24发布

在下面的单元测试代码:

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

第三行失败,即使功能是有效地从骨干事件绑定调用,由控制台demo'd。

这是非常令人沮丧,并动摇了我对sinon.js是否适合我的测试应用骨干信心。 我是不是做错了什么,或者这是与兴农如何检测是否东西一直被称为一个问题吗? 有没有解决办法?

编辑:这是一个解决方案,我的具体的例子,根据公认的答案的猴子打补丁方法。 虽然其在测试本身额外的设置几行代码,(我不需要的模块功能更多),它能够完成任务。 谢谢, 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!
}); 

Answer 1:

调用this.spy(this.testModel, 'doSomething')取代了testModel.doSomething用的方法新的包装方法 :

VAR =间谍sinon.spy(对象, “方法”);

创建一个间谍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);

比它是你已经附加了间谍后。 骨干事件调度程序调用原始的doSomething方法,但一个不具备兴农仪器。 当你调用doSomething手动,你调用新功能spy添加一个确实有兴农仪器。

如果你想使用兴农,以测试你的骨干事件,那么你就必须安排有兴农spy绑定任何事件处理程序和这可能意味着挂钩到之前应用于模型调用initialize

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

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

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

您也可以尝试的东西,如子类模型:

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

然后使用TestModel代替型号,这将给你的仪表版的ModelTestModel而不必包含您的正常生产就绪里面一堆测试代码Model 。 不足之处是其他任何使用Model需要被继承/修补/ ...使用TestModel代替。

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

您也许能绕过TestModel问题:

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

但你必须得到正确的顺序,以确保每个人都使用的新Model ,而不是旧的。

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



文章来源: QUnit, Sinon.js & Backbone unit test frustration: sinon spy appears to fail to detect Backbone Model event callbacks