存根一个 jQuery 选择器调用?

我正在努力提高对我的 JavaScript 进行单元测试的能力.我有以下代码:

I'm trying to get better at unit testing my JavaScript. I have the following code:

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

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

My test runner doesn't have the #category input on the page, so how would I stub/mock out the jQuery selector here? I've looked at both the jasmin and sinon documentation, but can't figure out how to get them to work here, since their stubs operate on objects, which $ is not.

推荐答案

这里的问题是 $() 是一个函数,它返回一个对象,方法是 val().所以你必须存根 $() 以返回一个具有方法 val 的存根对象.

The problem here is that $() is a function that returns an object with the method val(). So you have to stub $() to return a stubbed object having the method val.

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

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

But the main mistake here is to let the code you want to test call the function $() to create new instances. Why? Its best practice to create no new instances in your class, but to pass them into the constructor. Let's say you have function that will get a value out of an input, double it, and write it back to another:

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

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

In this case you create 2 new objects by calling $(). Now you have to stub $() to return a mock and a stub. Using the next example you can avoid this:

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

虽然,在第一种情况下,您必须存根 $ 才能返回存根,而在第二种情况下,您可以轻松地将存根和间谍传递到您的函数中.

While, in the first case you have to stub $ to return a stub, in the second case you can easily pass a stub and a spy into your function.

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

So the sinon test for the second one would look like this:

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.

So, as you have no dom elements here, you can simply test your application logic with no need to create the same dom as in your app.

相关文章