QUnit入门 (一)

  作者Aurelio De Rosa jQuery in Action(一定翻了几遍了吧) 第三版 和 Instant jQuery Selectors 的作者,并且是拥有着超过五年的HTML, CSS, Sass, JavaScript 和 PHP的开发经验的全栈(full-stack)和webapp开发工程师。不但精通JavaScript和 HTML5 APIs,而且也在web安全、可访问性、性能和方面有着深刻的造诣。(sitepoint:http://www.sitepoint.com/author/aderosa/)

  软件测试是给定一组输入值,比较真实值和期待值之间异同的过程。软件测试,特别是单元测试对于软件开发人员是必不可少的。不幸运的是,许多开发人员非常惧怕单元测试。

  JS里面有许多可以供我们选择进行单元测试的框架。比如,Mocha, Selenium, jasmine 和 QUnit。本文将重点讲述Qunit,Qunit 由开发了许多大名鼎鼎的js库,包括了的jQuery 、jQuery UI等的Jquery团队(jQuery team)开发。

  1、配置QUnit。

  QUnit本身非常低简单,并且非常方便去使用。主要的概念可以花费几个小时内掌握。

  首先安装QUnit,有三种方式:

    官网下载源文件; 引用CDN; 使用 bower 安装( bower install --save-dev qunit );  使用npm安装( npm install --save-dev qunitjs ) ;

    除非开发的项目非常简单或者项目准备发布到生产环境,否则不建议使用cdn的方式。在本文中我们使用第一种引入QUnit。在QUnit官网下载最新版的 qunit-1.20.0.js 和 qunit-1.20.0.css。创建一个html文件,内容如下:

 1 <!DOCTYPE html>
 2 <html>
 3    <head>
 4       <meta charset="utf-8">
 5       <title>QUnit Example</title>
 6       <link rel="stylesheet" href="../js/qunit/qunit-1.20.0.css">
 7    </head>
 8    <body>
 9       <div id="qunit"></div>
10       <div id="qunit-fixture"></div>
11       <script src="../js/qunit/qunit-1.20.0.js"></script>
12    </body>
13 </html>

   在body里面有两组div标签,div#qunit是QUnit用来显示测试结果的容器。div#qunit-fixture是QUnit留给开发者自己使用的,这个容器允许开发者测试添加,修改或者移除的dom代码,使开发者不必再为在每个test后为清理dom树而担忧。如果将在代码执行过程中创建html防止在这个div内,QUnit将帮助我们重置掉这些代码,恢复到初始状态。

   下面来看如何编写使用QUnit进行测试。

  2、使用QUnit创建一个测试(test)。

  QUnit创建test有两个方法:QUnit.test()和QUnit.asyncTest()。正如它们的命名,QUnit.test()常常用来测试同步运行的代码,QUnit.asyncTest()常常测试异步运行的代码。在这一小节,主要讲解如何使用QUnit.test()测试同步运行的代码。

  QUnit.test(name, testFunction)

   第一个参数name是用来标记test名称的字符串。第二个参数,testFunction是一个函数,包含了一个asset作为它的参数。asset包含了许多可供我们断言的方法。建立一个test。

QUnit.test('My first test', function(assert) {
     // Assertions here... 
});

  上面的代码段创建了一个名称为"My first test"的test和没有包含任何断言的一个空函数。下面我们来了解

  3、assert断言方法

  断言(Assertions)能够校验我们的代码是否如我们期望的那样运行,是软件测试的核心。QUnit有许多方法可以校验。asset作为QUnit.test()的回调函数的第一个参数。

  罗列了asset的主要方法和它们的主要用法:

  deepEqual(value, expected[, message]) : 递归性严格比较的,针对所有的javascript类型。如果真实值和期待值(expected)属性,属性值都一样并且和有同样的prototype的话,断言通过。

   notDeepEqual(value, expected[, message]):与deepEqual()类似,但是用于比较不相等。

  equal(value, expected[, message]) : 真实值和期待值(expected )是否相等,通过非严格方式的 "==",可能会转换类型。

  notEqual(value, expected[, message]) : 与equal()类似,但是用于判断不想等(转换类型的不相等)。

  strictEqual(value, expected[, message])真实值和期待值(expected )是否相(===)

  notStrictEqual(value, expected[, message]) : 与strictEqual相反,比较不全等。

  propEqual(value, expected[, message]) : 比较真实和期待(expected的对象的属性和属性值是否相同,相同断言通过。(注意和deepEqual的区别。

  notPropEqual(value, expected[, message]) : 与propEqual相反。

  ok(value[, message]:如果断言的第一个参数value为true,断言通过。

 throws(function [, expected ] [, message ]) : 判断函数是否抛出一个异常,第二个参数可选,代表不一定要检测抛出异常的类型。

 方法的参数:
 value:等待比较的值,值可以由函数返回或者是对象的一个方法或者一个变量;

 expected : 拿来作对比的值 。在throws()方法中, expected 可以是一个错误对象或者错误对象的实例、错误函数或者构造函数。或者是一个正则表达式 //todo
message : 一个可用来描述断言的字符串;  
function:要执行的应该返回错误的函数;
 

现在:你应该了解了上面的断言方法和它们参数的含义,下面来看一些代码实例。
 1 var SEX = [ 'unsigned', 'man', "women" ];
 2 
 3 var Person = function (name, sex) {
 4     this.name = name;
 5     this.sex = sex === undefined || SEX.contains(sex = sex.toLowerCase()) ? sex : SEX[ 0 ];
 6     return this;
 7 };
 8 
 9 Person.prototype.selfIntroduction = function () {
10     console.log('I\'m %s , sex is %s', this.name, this.sex);
11 };
12 
13 var person1 = new Person('Grace', SEX[ 0 ]);
14 var person2 = new Person('Bodhi', 'MAN');
15 var person3 = new Person('Grace', SEX[ 0 ]);
16 
17 QUnit.test("test strictEqual", function (assert) {
18     assert.strictEqual(person1.name, 'Grace', 'strictEqual test pass');
19     assert.notStrictEqual(person1.name, 'Bodhi', 'person2 test pass');
20 });
21 QUnit.test('test array', function (assert) {
22     assert.ok([ 5, 8, 9 ].contains(9), 'test contains pass');
23     assert.notOk([ 5, 8, 9 ].contains(10), 'test not contains pass');
24 });
25 QUnit.test('test equal', function (assert) {
26     assert.strictEqual(person1, person3, 'test person1 and person3 strictEqual pass');
27     assert.propEqual(person1, person3, 'test person1 and person3 propEqual pass.');
28 });
29 QUnit.test('test propEqual', function (assert) {
30     assert.propEqual(person1, {name: 'Grace', sex: 'unsigned'}, 'propEqual pass when prototype is not same.');
31     assert.propEqual(person1, {
32         name: 'Grace',
33         sex: 'man'
34     }, 'propEqual pass when prototype is not same and the value of sex is different.');
35 });
 
 
 1 if (!Array.prototype.indexOf) {
 2     Array.prototype.indexOf = function (elt) {
 3         var len = this.length >>> 0;
 4         var from = Number(arguments[1]) || 0;
 5         from = (from < 0)? Math.ceil(from) : Math.floor(from);
 6         if (from < 0){
 7             from += len;
 8         }
 9         for (; from < len; from++) {
10             if (from in this && this[from] === elt){
11                 return from;
12             }
13         }
14         return -1;
15     };
16 }
17 
18 if (!Array.prototype.contains) {
19     Array.prototype.contains = function (elt) {
20         return (this.length >>> 0) !== 0 && this.indexOf(elt) !== -1;
21     }
22 }

      在上面的例子中,第一个(test strictEqual)使用===进行比较,两个都通过。assert.ok中如果第一个参数返回true,测试通过。assert.strictEqual比较两个对象当且仅当两个对象指向了同一个地址时候才相等,所以第三个测试不通过。

assert.propEqual会忽略原型仅进行属性和值的比较。在propEqual的源码中有这么一段:

 1 function objectValues ( obj ) {
 2     var key, val,
 3         vals = QUnit.is( "array", obj ) ? [] : {};
 4     for ( key in obj ) {
 5         if ( hasOwn.call( obj, key ) ) {
 6             val = obj[ key ];
 7             vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
 8         }
 9     }
10     return vals;
11 }

  在使用propEqual比较时,会根据obj的类型确定一个空的待返回值的类型。遍历obj中每一个属于自己的属性,如果属性值(value)是一个对象,就以递归(前序遍历)的方式将新的返回的对象中。不会去检查obj的constructor。

  

 

  

  

 

 



 

你可能感兴趣的:(QUnit入门 (一))