Javascript 使用jasmine.js和sinon.js不会调用backbone.js单击事件间谍
我正在尝试使用backbone.js、jasmine.js和sinon.js测试按钮点击。但是下面的测试用例失败了。我正在用间谍追踪它是否被呼叫。 你能帮我做这个吗 谢谢 新任务模板Javascript 使用jasmine.js和sinon.js不会调用backbone.js单击事件间谍,javascript,jquery,backbone.js,jasmine,sinon,Javascript,Jquery,Backbone.js,Jasmine,Sinon,我正在尝试使用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
<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>
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();
});
});
茉莉花测试用例
<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>
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.
表示您正在将单击事件绑定到视图的this.el
-根元素,在您的情况下,该元素具有ID新建任务部分
。您需要将它绑定到#add_new_task
,我想这是您的“addtask”按钮-这应该可以修复它
events:{
"click #add_new_task" : "addTask"
},
更新:
$(“#添加#新#任务”)找不到元素,因为视图未添加到文档DOM树中。使用
this.view.$('add#new_task')
它应该可以工作,因为它将在视图中存储的分离片段中搜索元素。您的方法存在一些问题。首先,您监视您想要测试的类,这不是单元测试应该使用的方式,因为您测试的是类的内部逻辑,而不是它的行为。其次,这也是测试失败的原因,因为您没有将视图附加到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]()
毕竟,你必须决定什么方法适合你的需要。使用backbones helpers的更精简的代码或对jquery、DOM和backbone依赖性更小的更好的可测试代码。问题是,在backbone已经将click事件直接绑定到addTask函数(它在构建视图期间执行此操作)之后,您添加了spy。所以你的间谍不会被召唤 在构建视图之前,请尝试将spy附加到视图的原型。像这样:
this.addTaskSpy = sinon.spy(T.views.NewViewTask.prototype, 'addTaskSpy');
this.view = new T.views.NewTaskView();
然后记住将其移除:
T.views.NewViewTask.prototype.addTaskSpy.restore()
视图在DOM中的何处呈现自身?模板是否在规范中可用?Jasmine spec runner的DOM中可能不存在“添加新任务”按钮,因此
$(“添加新任务”)。单击()代码>无效。如果您确定视图是使用正确的模板呈现的,那么可以使用NewTaskView的元素作为jquery函数的上下文:$('add#new_task',this.view.el)。单击()代码>。我想这个问题已经在这里得到了回答:事实上,我也有这个“单击#添加#新"任务”的问题,事件被触发,因为我在addTask方法中有console.log行。但是expect(spy).tohavebeencall()失败;可能是我的绑定错误?如果#add_new_任务不在此视图中,它不是绑定在错误的位置吗?jQuery的工作方式是搜索附加到文档的DOM树,但是如果您自己不将主干视图元素附加到DOM树,它就不在那里。这就是为什么需要使用主干jQuery find(Backbone.View$方法),它将搜索的上下文设置为视图的el
,从而可以在尚未连接到DOM树的DOM中进行搜索#add_new_任务正好在视图中-只是视图不在文档中-它只是保存在内存中,等待插入执行$(body).append(this.view.el)
渲染后,您将看到它应该可以工作,而不必将$('add_new_任务')更改为this.view.$('add_new_任务')
(或者您可以编写它$('add#u new_task',this.view.el)
,如果您愿意的话)。这是100%正确的行为。jasmine jquery
助手可以帮助您处理设备:jasmine不是一个单元测试框架-它是BDD框架,他所做的非常好-测试一个行为不确定您的观点。监视您想要测试的类没有多大意义。因为这不是您的类的行为l一个特定的函数本身。更改此函数的名称将破坏测试,但不会破坏行为。另一个想法是,我认为最好尽可能多地模拟依赖项。使用依赖项注入会更容易,因为您不必在测试前加载夹具,对其触发单击事件并在战后清理ds.这个答案应该被接受。谢谢,这太令人头痛了!完全有道理!谢谢!:)我不清楚的是:如果我只想监视原型的一个实例,为什么我需要监视原型。这不可能吗?这很有效。比必须更改代码才能进行测试要好得多。+1谢谢!只是一个小注释,因为要监视的方法是addTask,它应该是:this.addTaskSpy=sinon.spy(T.views.NewViewTask.prototype,'addTask')
和T.views.NewViewTask.prototype.addTask.restore()