我在尝试测试视图是否与事件绑定时遇到了一些有趣的磨难。在骨干中,我们通常使用以下行:something.bind("change", this.render);
绑定初始化方法中的事件。在我的测试中,我想确保已设置此绑定,因此我执行了以下操作:
this.myView = new MyView();
spyOn(this.myView, "render");;
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();
但是,那不行。因为绑定发生在MyView的初始化函数中,所以事件get被绑定到myView的渲染函数AT THAT TIME。因此,当您添加间谍时,它会包装渲染功能并将其设置回myView.render。但是由第一个绑定创建的闭包仍然存在,我们完全是胡说八道。那么我们能做些什么呢?我所做的是将我的绑定调用移动到单独的函数,例如:
myView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, "render");
this.initialize_model_bindings();
},
initialize_model_bindings: function(){
something.bind("change", this.render);
},
render: function(){ //... }
});
然后我的测试看起来像:
this.myView = new MyView();
spyOn(this.myView, "render");
this.myView.initialize_model_bindings();
this.legendView.groupData.trigger("change");
expect(this.legendView.render).toHaveBeenCalled();
这很有效,但我正在寻找更好的解决方案。感谢
答案 0 :(得分:12)
我已经设法使用原型修补来实现这一目标。在创建视图实例之前,spyOn
构造函数的原型。
spyOn(MyView.prototype, 'changeSelected');
var view = new MyView();
view.selectSomething();
expect(view.changeSelected).toHaveBeenCalled();
答案 1 :(得分:5)
您可以尝试监视某些内容,而不是监视回调。然后测试绑定被称为w /适当的参数。到目前为止,这对我有用。我正在使用sinon.js而不是茉莉花的内置间谍。 sinon.js使得更容易测试传递给相同方法调用的堆栈中的方法调用的args(例如,在视图init中绑定的一堆调用)。所以我没有单独用茉莉花测试这个想法,但相信它应该是可能的。
spyOn(this.legendView.groupData, 'bind');
this.myView = new MyView();
expect(this.legendView.groupData.mostRecentCall.args).toEqual('change', this.myView.render); // example!! only works if testing a single call to bind or the last call in a series (ie mostRecentCall)
和w / sinon.js
sinon.spy(this.legendView.groupData, 'bind');
this.myView = new MyView();
expect(this.legendView.groupData.bind.calledWith('change', this.myView.render); // works w/ any number of calls to bind
答案 2 :(得分:3)
我通过监视我的渲染函数调用的函数解决了这个问题。所以在你的例子中:
myView = Backbone.View.extend({
initialize: function(){
_.bindAll(this, "render");
something.bind("change", this.render);
},
someOtherFunction: function(){}, //this function only called from render
render: function(){ this.someOtherFunction(); /* rest of render function */ }
});
测试看起来像:
this.myView = new MyView();
spyOn(this.myView, "someOtherFunction");
this.myView.something.trigger("change");
expect(this.myView.someOtherFunction).toHaveBeenCalled();
然后我为someOtherFunction做了一些单独的测试。
答案 3 :(得分:2)
你应该考虑看看Sinon.js。你可以存根/模拟render()调用,甚至不必担心'someOtherFunction()'。
答案 4 :(得分:1)
这可能与Backbone内部结构太紧密相关,但您可以手动检查回调链:
expect(this.legendView.groupData._callbacks['change']).toContain(this.myView.render)
答案 5 :(得分:0)
我遇到了同样的问题并改变了我的视图代码:
this.model.on('change', this.render, this);
为:
this.model.on('change', function () {
this.render();
}, this);
我的茉莉花测试按预期工作。