在使用 Karma 和 Sinon 时,我如何能够测试绑定到事件总线的 Backbone 模型的方法是否已触发?

How am I able to test that a Backbone model's method bound to the event bus has fired when using Karma and Sinon?

当测试 backbone 模型的事件已用 sinon 间谍触发时,它错误地出错:expected doSomething to be called once but was called 0 times,即使它似乎是在将控制台日志放入方法主体时执行的。测试函数如下所示:

it('Y U NO WORK', function() {
    const events = {};
    _.extend(events, Backbone.Events);
    const Model = Backbone.Model.extend({
        initialize: function() {
            this.listenTo(events, 'doSomething', this.doSomething);
        },
        doSomething: function() {},
    });
    const model = new Model();
    const spy = sinon.spy(model, 'doSomething');
    events.trigger('doSomething');
    sinon.assert.calledOnce(spy);
});

我知道要解决这个问题,您必须在 new Model() 调用之前的行中像 const spy = sinon.spy(Model.prototype, 'doSomething'); 一样将 sinon spy 放在模型的原型上,但是它似乎可以正常工作放入模型实例,如下所示:

it('And this does work', function() {
    const Model = Backbone.Model.extend();
    const model = new Model();
    const spy = sinon.spy(model, 'set');
    model.set('foo', 'bar');
    sinon.assert.calledOnce(spy);
});

想知道为什么它需要在第一个实例中放在模型的原型上,但在第二个实例中却适用于模型实例?

Spy 将原始方法替换为自定义方法,以了解何时调用它(它保留对原始方法的引用以便稍后恢复)。所以在第一种情况下,你在创建间谍之前设置了一个事件监听器。事件系统实际上直接引用原始方法,而不是间谍。 Spy 对此无能为力,Spy 不知道它何时被调用。

在设置事件侦听器之前需要先设置间谍,例如:

it('Y U NO WORK', function() {
    var spy;
    const events = {};
    _.extend(events, Backbone.Events);
    const Model = Backbone.Model.extend({
        initialize: function() {
            spy = sinon.spy(this, 'doSomething');
            this.listenTo(events, 'doSomething', this.doSomething);
            //now same as this.listenTo(events, 'doSomething', spy);
        },
        doSomething: function() {},
    });
    const model = new Model();
    events.trigger('doSomething');
    sinon.assert.calledOnce(spy);
});

或者避免直接引用原始方法,例如:

this.listenTo(events, 'doSomething', function() {
  //by the time this is invoked, original has been replaced with spy
  this.doSomething();
});

它会起作用,因为它没有保留对原始方法的引用,方法调用是动态的