我正在尝试使用backbone.js,jasmine.js和sinon.js测试按钮单击。但是以下测试用例失败了。我正在使用间谍来追踪它是否被召唤。 你能帮帮我吗?
感谢。
新任务模板
<script id='new_task_template' type='text/template'>
<input type='text' id='new_task_name' name='new_task_name'></input>
<button type='button' id='add_new_task' name='add_new_task'>Add Task</button>
</script>
NewTaskView
T.views.NewTaskView = Backbone.View.extend({
tagName: 'section',
id: 'new_task_section',
template : _.template ( $("#new_task_template").html() ),
initialize: function(){
_.bindAll( this, 'render', 'addTask');
},
events:{
"click #add_new_task" : "addTask"
},
render: function(){
$(this.el).html( this.template() );
return this;
},
addTask: function(event){
console.log("addTask");
}
});
茉莉花测试用例
describe("NewTaskView", function(){
beforeEach( function(){
this.view = new T.views.NewTaskView();
this.view.render();
});
it("should #add_new_task is clicked, it should trigger the addTask method", function(){
var clickSpy = sinon.spy( this.view, 'addTask');
$("#add_new_task").click();
expect( clickSpy ).toHaveBeenCalled();
});
});
茉莉花输出
NewTaskView
runEvents
runshould #add_new_task is clicked, it should trigger the addTask method
Expected Function to have been called.
答案 0 :(得分:41)
问题是在骨干已经将click事件直接绑定到addTask函数之后添加间谍(它在构建View期间执行此操作)。因此,你的间谍不会被召唤。
尝试在构建之前将间谍附加到View 的原型。像这样:
this.addTaskSpy = sinon.spy(T.views.NewViewTask.prototype, 'addTaskSpy');
this.view = new T.views.NewTaskView();
然后记得删除它:
T.views.NewViewTask.prototype.addTaskSpy.restore()
答案 1 :(得分:0)
events:{
"click" : "addTask"
},
表示您将click事件绑定到this.el
- 视图的根元素,在您的情况下,该元素具有ID new_task_section
。你需要将它绑定到#add_new_task
,这是我假设的“添加任务”按钮 - 这应该解决它!
events:{
"click #add_new_task" : "addTask"
},
更新
$(“#add_new_task”)将找不到元素,因为视图未添加到文档DOM树中。使用this.view.$('#add_new_task')
,它应该工作,因为它将搜索存储在视图中的分离片段中的元素。
答案 2 :(得分:0)
您的方法存在一些问题。首先,你要监视你想要测试的课程,而不是单元测试的工作方式,因为你要测试你班级的内在逻辑而不是它的行为。其次,这就是你的测试失败的原因,你没有将你的观点附加到DOM中。因此,要么将el附加到DOM,要么将click事件直接发送到el:$('#add_new_task', this.view.el).click()
。
顺便说一下。 backbones创建元素和绑定事件的方式使得编写好的单元测试很困难,因为你被迫使用DOM和jquery。编写可测试代码的更好方法是始终将所有依赖项传递给构造函数,并且不要在代码中创建新实例,因为很难测试这些对象。因此,在您的情况下,将构造函数中的el对象作为jquery对象和手动事件注入会更容易。这样做就可以测试你的类而不依赖于DOM或jquery。
所以在你的情况下,构造函数看起来像这样:
initialize: function(){
this.el.click(_.bind( this, 'addTask'));
}
你的考试:
var el = {click: function(){}};
spyOn( el, 'click');
new T.views.NewTaskView({el: el});
expect(el.click).toHaveBeenCalled(); //test the click event was bind
//call the function that was bind to the click event,
//which is the same as trigger the event on a real DOM object
el.click.mostRecentCall.args[0]()
毕竟你必须决定哪种方法适合你的需要。具有主干帮助程序的精简代码或更好的可测试代码,对jquery,DOM和主干的依赖性更小。