使用jasmine.js和sinon.js调用backbone.js click事件间谍

我正在尝试使用backbone.js,jasmine.js和sinon.js测试按钮单击。 但是以下测试用例失败了。 我正在使用间谍来追踪它是否被召唤。 你能帮我解决这个问题吗?

谢谢。

新任务模板

    

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. 

问题是你在骨干已经将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() 
 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')它应该工作,因为它将搜索存储在视图中的分离片段中的元素。

您的方法存在一些问题。 首先,你要监视你想要测试的课程,而不是unit testing的工作方式,因为你测试你的类的内在逻辑而不是它的行为。 其次,这就是你的测试失败的原因,你没有将你的观点附加到DOM中。 因此,要么将el $('#add_new_task', this.view.el).click()到DOM,要么将click事件直接发送到el: $('#add_new_task', this.view.el).click()

顺便说一句。 backbones创建元素和绑定事件的方式使得编写好的unit testing很困难,因为你被迫使用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和主干的依赖性更小。