存根jQuery选择器调用?

我正在努力改进unit testing我的JavaScript。 我有以下代码:

var categoryVal = $('#category').val(); if (categoryVal === '') { doSomething(); } 

我的测试#category器在页面上没有#category输入,那么我如何在这里存根/模拟jQuery选择器呢? 我已经查看了jasmin和sinon文档,但无法弄清楚如何让它们在这里工作,因为它们的存根操作对象,而$不是。

这里的问题是$()是一个返回带有方法val()的对象的函数。 因此,您必须使用stub()来返回具有方法val的存根对象。

 $ = sinon.stub(); $.withArgs('#category').returns(sinon.stub({val: function(){}})); 

但这里的主要错误是让你想要测试的代码调用函数$()来创建新的实例。 为什么? 最好的做法是在类中不创建新实例,而是将它们传递给构造函数。 假设您有一个函数可以从输入中获取值,将其加倍,然后将其写回另一个:

 function doubleIt(){ $('#el2').val(('#el1').val() *2); } 

在这种情况下,您可以通过调用$()创建2个新对象。 现在你必须存根$()来返回一个模拟和一个存根。 使用下一个示例,您可以避免这种情况:

 function doubleIt(el1, el2){ el2.val(el1.val() *2); } 

虽然,在第一种情况下,你必须存根$返回存根,在第二种情况下,你可以轻松地将存根和间谍传递给你的函数。

所以第二个的sinon测试看起来像这样:

 var el1 = sinon.stub({val: function(){}}); el1.returns(2); var el2 = sinon.spy({val: function(){}}, 'val') doubleIt(el1, el2) assert(el2.withArgs(4).calledOnce) 

因此,由于此处没有dom元素,因此您只需测试应用程序逻辑,而无需在应用程序中创建相同的dom。

jQuery在引擎盖下使用了css选择器引擎Sizzle并且被解耦,所以它只有几个地方可以挂钩。你可以截取它以避免与dom的任何交互。

jQuery.find是一个重要的改变,以响应你想要的任何东西。 Sinon可以在这里使用或临时交换function。

例如

 existingEngine = jQuery.find jQuery.find = function(selector){ console.log(selector) } $(".test") //>> ".test" jQuery.find = existingEngine 

您还可以应用具有后备的特定捕获条件

 existingEngine = jQuery.find jQuery.find = function(selector){ if(selector=='blah'}{ return "test"; } return existingEngine.find.apply(existingEngine, arguments) } 

在我最近的工作中,我创建了一个虚拟对象,它像dom节点一样响应并将其包装在jQuery对象中。 然后,这将正确响应val()并使所有jquery方法都出现在它期望的位置。 就我而言,我只是从表单中提取值。 如果你正在进行实际的操作,你可能需要比这更聪明,或许用jQuery创建一个代表你期望的临时dom节点。

 obj = { value: "blah", type: "text", nodeName: "input", } $(obj).val(); // "blah" 

如果您使用的是Backbone.js和Jasmin,这是一个很好的测试视图的指南。 向下滚动到“视图”部分。

http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html

没错,存根操作对象。 我想创建一个视图存根就像这样。

 this.todoViewStub = sinon.stub(window, "TodoView") .returns(this.todoView); 

只是为了能够以后渲染视图。

 this.view.render(); 

换句话说,将’#category’div附加到testrunner的DOM,以便$可以对其进行操作。 如果您的“#category”div不在this.view中,那么您可以创建一个test.html页面,在该页面中运行您的隔离测试。 这是Javascript MVC框架中的常见模式,我更习惯于Backbone。

这是一个简单的JMVC应用程序结构示例:

 /todo /models todo.js /list /views init.tmpl listItem.tmpl list.css list.js (Controller) unitTest.js (Tests for your list.) list_test.html (A html for your unit tests to run on.) 

有了这个设置,你可以在list_test.html中包含“#category”div,如果你还没有将它放在其中一个视图中。