使用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和主干的依赖性更小。