Javascript单元测试

看到一个面试题,问是否用过单元测试,赶紧查查资料,总结如下:

1、什么是单元测试

在计算机编程中,单元测试(又称为模块测试)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。——维基百科

2、为什么进行JavaScript单元测试

现在最主流的JavaScript单元测试框架就是Qunit,下面只介绍这一个

  • 使用起来非常方便,有漂亮的外观和完整的测试功能(包括异步测试);

  • 非常简单,容易上手,目前公开的API只有19个;

  • 不需要依赖其它任何软件包或框架,只要能运行JS的地方就可以,QUnit本身只有一个JS文件和CSS文件,当然如果需要可以和jQuery等其它框架集成;

最重要的是:

  • 如果你以前从未写过任何单元测试,你可能直接将你的代码应用到网站上,点击一会看看是否有什么问题出现,并且尝试去解决你所发现的问题,采用这种方法会有很多的问题。

  • 首先,这是非常乏味的。点击其实并不是一项简单的工作,因为需要保证每一个东西都被点击到而且极有可能漏掉一两个。其次,为测试做的每一件事情都是不可重用的,这就意味着它很难回归。什么是回归?想像一下,你写了一些代码并测试他们,修复了所有你发现的缺陷,然后发布。这时,一个用户发过来一些关于新的bug的反馈,并且有一些新的需求。你又回到代码中,处理这些新的bug,并增加新的功能。接下来可能会发生的就是一些旧的缺陷又重现了,这就叫“回归”。这样,你就不得不重新点击一遍,而且有可能你还找不到这些旧的缺陷;即使你这么做,这还需要一段时间才能弄清楚你的问题是由回归引起的。使用单元测试,你写测试用例去发现缺陷,一旦代码被修改,您通过测试再筛选一次。一旦出现回归,一些测试用例一定会失败,你可以很容易地认出他们,知道哪部分代码包含了错误。既然你知道你刚才修改了什么,就可以很容易地解决问题。

  • 单元测试的另外一个尤其是对于Web开发的优点:让跨浏览器兼容性测试变得更容易。仅仅在不同浏览器中运行你的测试用例,一旦某个浏览器出现问题,修复它并重新运行这些测试用例,确保不会在别的浏览器引起回归,一旦全部通过测试,就可以肯定的说,所有的目标浏览器都支持。

3、怎么进行单元测试

QUnit所有的API可以分为三类:Setup,Assertions,Asynchronous Testing,下面就分别对这些API做些介绍:

Setup:

test( name, [expected], testFun ) 代表QUnit中的一个测试

name:要测试的名称,比如“加法函数”或“add”等

expected:可选参数,用来表示该测试函数的断言的数量,是个正整数

testFun:一个函数,所有的测试代码都应该包括在该函数里,通常这是一个匿名函数。
例:
test(“add function”, 1, function() {
    equal(add(1, 2), 3);
});

asyncTest( name, [expected], testFun ) 代表QUnit中的一个异步测试,参数同test

expect( amount ) 用在测试函数中,用于声明测试断言的数量,这个函数和test中的expected参数的作用是一样的。主要作用就是检查你声明的个数和你写的断言的实际个数是否一致。

module( name, [lifecycle] ) 主要用于测试函数的分组,一个module函数为一个分组,比如module(“validate”)表示后面的测试用例都是validate相关的代码,或者module(“common.js”),表明后面的测试用例都是common.js里面的代码。一个测试文件可以写多个module。

name:分组或者模块的名称

lifecycle:可选参数,它是一个对象,可以设置setup和teardown回调函数
例:
module(“common.js”, 
    {
        setup:function(){},
        teardown: function() {} 
    }
);
//setup:在module开始之前执行,可以为该module下面的测试代码做一些准备工作
//teardown:将会在该module的所有测试代码执行后执行,比如做一些清理还原工作等。

Assertions:

ok( state, [message] ) 断言。state值为true时表示通过,否则失败。

equal( actual, expected, [message] ) 比较参数actual和expected是否相等,相当于 ==

notEqual( actual, expected, [message] ) 比较两个参数是否不相等,相当于 !=

deepEqual( actual, expected, [message] ) 主要用于数组和对象等类型的值是否相等,会递归遍历它们所包含的值是否相等。

notDeepEqual( actual, expected, [message] ) 主要用于数组和对象等类型的值是否不相等,会递归遍历它们所包含的值是否不相等。

strictEqual( actual, expected, [message] ) 比较两个参数是否严格相等,相当于 ===

notStrictEqual( actual, expected, [message] ) 比较两个参数是否不严格相等,相当于 !==

throws( block, expected, [message] ) 测试block函数是否抛出一个异常,抛出则通过,不抛则失败。

block:我们要测试的函数

expected:可选参数,是一个类型,用来验证第一个函数抛出的异常是否是我们预期的类型。

例:
function CustomError( message ) {
    this.message = message;
}

CustomError.prototype.toString = function() {
    return this.message;
};
throws(
    function() {
        throw new CustomError(“some error description”);
    },
    CustomError,
    "raised error is an instance of CustomError"
);

Asynchronous Testing:

stop( [increment] ) 停止测试的运行,用于异步测试。在异步测试时一般先把QUnit的test runner停下来。

increment:增加停止的时间。

start( [decrement] ) 当异步调用成功后就应该把停止的test runner启动起来让它接着往前跑

decrement:用来减少停止的时间。
例:

test( "a test", function() {
    stop();
    var result = null;
    $.ajax(
        url,
        {},
        function(data){
            result = data;
        }
    );
    setTimeout(function() {
        equals(result, "success" );
        start();
    }, 150 );
});

Javascript单元测试_第1张图片
Javascript单元测试_第2张图片
Javascript单元测试_第3张图片

你可能感兴趣的:(js)