swi*_*ams 22 javascript jquery unit-testing jasmine sinon
我正在努力改进单元测试我的JavaScript.我有以下代码:
var categoryVal = $('#category').val();
if (categoryVal === '') {
doSomething();
}
Run Code Online (Sandbox Code Playgroud)
我的测试运行器没有#category页面上的输入,那么我将如何在这里存根/模拟jQuery选择器?我看了两个茉莉和兴农文档,但无法弄清楚如何让他们在这里工作,因为他们的存根对象进行操作,这$是没有的.
And*_*rle 35
这里的问题是,这$()是一个使用该方法返回对象的函数val().因此,您必须使用stub()来返回具有方法val的存根对象.
$ = sinon.stub();
$.withArgs('#category').returns(sinon.stub({val: function(){}}));
Run Code Online (Sandbox Code Playgroud)
但这里的主要错误是让你想要测试的代码调用函数$()来创建新的实例.为什么?最佳实践是在类中不创建新实例,而是将它们传递给构造函数.假设您有一个函数可以从输入中获取值,将其加倍,然后将其写回另一个:
function doubleIt(){
$('#el2').val(('#el1').val() *2);
}
Run Code Online (Sandbox Code Playgroud)
在这种情况下,您可以通过调用创建2个新对象$().现在你必须存根$()以返回模拟和存根.使用下一个示例,您可以避免这种情况:
function doubleIt(el1, el2){
el2.val(el1.val() *2);
}
Run Code Online (Sandbox Code Playgroud)
虽然,在第一种情况下,你必须存根$返回存根,在第二种情况下,你可以轻松地将存根和间谍传递给你的函数.
所以第二个的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)
Run Code Online (Sandbox Code Playgroud)
因此,由于此处没有dom元素,因此您只需测试应用程序逻辑,而无需在应用程序中创建相同的dom.
小智 10
jQuery在引擎盖下使用了css选择器引擎Sizzle并且被解耦,所以它只有几个地方可以挂钩.你可以截取它以避免与dom的任何交互.
jQuery.find是一个重要的改变,以响应你想要的任何东西.Sinon可以在这里使用或临时交换功能.
例如
existingEngine = jQuery.find
jQuery.find = function(selector){ console.log(selector) }
$(".test")
//>> ".test"
jQuery.find = existingEngine
Run Code Online (Sandbox Code Playgroud)
您还可以应用具有后备的特定捕获条件
existingEngine = jQuery.find
jQuery.find = function(selector){
if(selector=='blah'}{ return "test"; }
return existingEngine.find.apply(existingEngine, arguments)
}
Run Code Online (Sandbox Code Playgroud)
在我最近的工作中,我创建了一个虚拟对象,它像dom节点一样响应并将其包装在jQuery对象中.然后,这将正确响应val()并使所有jquery方法都出现.在我的情况下,我只是从表单中提取值.如果你正在进行实际的操作,你可能需要比这更聪明,或许用jQuery创建一个代表你期望的临时dom节点.
obj = {
value: "blah",
type: "text",
nodeName: "input",
}
$(obj).val(); // "blah"
Run Code Online (Sandbox Code Playgroud)