NodeJs测试框架Mocha的安装与使用


Posted in NodeJs onMarch 28, 2017

Mocha是运行在nodejs和浏览器下的JavaScript的单元测试框架,官方文档在https://mochajs.org/,相当的容易上手和好用,单元测试框架其实都差不多,基本都包含下面内容:

用于写测试用例的宏,属性或者函数
断定库, 用于测试是否可以通过
辅助库,如hook库(测试前后调用某些函数或者方法),异常检查(某些函数在某些参数的情况下抛出异常), 输入组合(支持多排列的参数输入组合)等。
支持IDE的集成
下面就按照官方文档的顺序来简明扼要的

安装与初步的使用

在控制台窗口中执行下列命令:

$ npm install -g mocha
$ mkdir test
$ $EDITOR test/test.js

可以写如下代码:

var assert = require('assert');
describe('Array', function() {
 describe('#indexOf()', function () {
  it('should return -1 when the value is not present', function () {
   assert.equal(-1, [1,2,3].indexOf(5));
   assert.equal(-1, [1,2,3].indexOf(0));
  });
 });
});

回到控制台:

$ mocha

 .

 ✔ 1 test complete (1ms)

这里mocha会查找当前文件目录下test文件夹下的内容,自动执行。

断定库

这个是判定测试用例是否通过,默认下可以用nodejs的assert库,与此同时,Mocha支持我们使用不同的断定库,现在可以支持下面的断定库,每个断定库的用法有一些差异,自己可以参考相应的文档。

1 should.js(https://github.com/shouldjs/should.js) BDD style shown throughout these docs (BDD模式,本文档用的都是这个断定库)
2 better-assert(https://github.com/tj/better-assert) c-style self-documenting assert()(C-模型下的断定库)
3 expect.js (https://github.com/Automattic/expect.js)expect() style assertions (expect模式的断定库)
4 unexpected(http://unexpected.js.org/) the extensible BDD assertion toolkit
5 chai(https://github.com/chaijs) expect(), assert() and should style assertions

同步代码

同步代码表示测试的是同步函数,上面的Array相关的例子代码就是。这个比较好理解。

异步代码

只所以有异步代码测试,原因是在nodejs上许多异步函数,如下面的代码中,只有done()函数执行完毕后,该测试用例才算完成

describe('User', function() {
 describe('#save()', function() {
  it('should save without error', function(done) {
   var user = new User('Luna');
   user.saveAsync(function(err) {
    if (err) throw err;
    done(); // 只有执行完此函数后,该测试用例算是完成。
   });
  });
 });
});

详解describe和it

上面的实例代码比较简单,那么什么是describe和it呢? 大致上,我们可以看出describe应该是声明了一个TestSuit(测试集合) ,而且测试集合可以嵌套管理,而it声明定义了一个具体的测试用例。 以bdd interface为例,具体的源代码如下:

/**
   * Describe a "suite" with the given `title`
   * and callback `fn` containing nested suites
   * and/or tests.
   */
  context.describe = context.context = function(title, fn) {
   var suite = Suite.create(suites[0], title);
   suite.file = file;
   suites.unshift(suite);
   fn.call(suite);
   suites.shift();
   return suite;
  };

   /**
   * Describe a specification or test-case
   * with the given `title` and callback `fn`
   * acting as a thunk.
   */

  context.it = context.specify = function(title, fn) {
   var suite = suites[0];
   if (suite.pending) {
    fn = null;
   }
   var test = new Test(title, fn);
   test.file = file;
   suite.addTest(test);
   return test;
  };

Hooks(钩子)

实际上这个在写unit test是很常见的功能,就是在执行测试用例,测试用例集合前或者后需要某个回调函数(钩子)。Mocha提供了before(),after(), beforeEach() 和aftetEach(),示例代码如下:

describe('hooks', function() {
 before(function() {
  // runs before all tests in this block
  // 在执行所有的测试用例前 函数会被调用一次
 });

 after(function() {
  // runs after all tests in this block
  // 在执行完所有的测试用例后 函数会被调用一次
 });

 beforeEach(function() {
  // runs before each test in this block
   // 在执行每个测试用例前 函数会被调用一次
 });

 afterEach(function() {
  // runs after each test in this block
  // 在执行每个测试用例后 函数会被调用一次
 });

 // test cases
});

hooks还有下列其他用法:

Describing Hooks - 可以对钩子函数添加描述,能更好的查看问题
Asynchronous Hooks (异步钩子): 钩子函数可以是同步,也可以是异步的,和测试用例一下,下面是异步钩子的示例代码:

beforeEach(function(done) {
  // 异步函数
  db.clear(function(err) {
   if (err) return done(err);
   db.save([tobi, loki, jane], done);
  });
 });

Root-Level Hooks (全局钩子) - 就是在describe外(测试用例集合外)执行,这个一般是在所有的测试用例前或者后执行。
Pending Tests (挂起测试)

就是有一些测试,现在还没有完成,有点类似TODO, 如下面的代码:

describe('Array', function() {
 describe('#indexOf()', function() {
  // pending test below 暂时不写回调函数
  it('should return -1 when the value is not present');
 });
});

Exclusive Tests (排它测试)

排它测试就是允许一个测试集合或者测试用例,只有一个被执行,其他都被跳过。如下面测试用例集合:

describe('Array', function() {
 describe.only('#indexOf()', function() {
  // ...
 });
   // 测试集合不会被执行
  describe('#ingored()', function() {
  // ...
 });
});

下面是对于测试用例:

describe('Array', function() {
 describe('#indexOf()', function() {
  it.only('should return -1 unless present', function() {
   // ...
  });
   // 测试用例不会执行
  it('should return the index when present', function() {
   // ...
  });
 });
});

需要说明的是,对于Hooks(回调函数)会被执行。

Inclusive Tests(包含测试)

与only函数相反,skip函数,将会让mocha系统无视当前的测试用例集合或者测试用例,所有被skip的测试用例将被报告为Pending。
下面是对与测试用例集合的示例代码:

describe('Array', function() {
  //该测试用例会被ingore掉 
 describe.skip('#indexOf()', function() {
  // ...
 });
  // 该测试会被执行
  describe('#indexOf()', function() {
  // ...
 });
});

下面例子是对具体的测试用例:

describe('Array', function() {
 describe('#indexOf()', function() {
   // 测试用例会被ingore掉
  it.skip('should return -1 unless present', function() {
   // ...
  });
   // 测试用例会被执行
  it('should return the index when present', function() {
   // ...
  });
 });
});

Dynamically Generating Tests(动态生成测试用例)

其实这个在很多其他的测试工具,如NUnit也会有,就是将测试用例的参数用一个集合代替,从而生成不同的测试用例。下面是具体的例子:

var assert = require('assert');

function add() {
 return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
  return prev + curr;
 }, 0);
}

describe('add()', function() {
 var tests = [
  {args: [1, 2],    expected: 3},
  {args: [1, 2, 3],  expected: 6},
  {args: [1, 2, 3, 4], expected: 10}
 ];
 // 下面就会生成三个不同的测试用例,相当于写了三个it函数的测试用例。
 tests.forEach(function(test) {
  it('correctly adds ' + test.args.length + ' args', function() {
   var res = add.apply(null, test.args);
   assert.equal(res, test.expected);
  });
 });
});

Interfaces(接口)

Mocha的接口系统允许用户用不同风格的函数或者样式写他们的测试用例集合和具体的测试用例,mocha有BDD,TDD,Exports,QUnit和Require 风格的接口。

BDD - 这个是mocha的默认样式,我们在本文中的示例代码就是这样的格式。
其提供了describe(), context(), it(), before(), after(), beforeEach(), and afterEach()的函数,示例代码如下:

describe('Array', function() {
  before(function() {
   // ...
  });

  describe('#indexOf()', function() {
   context('when not present', function() {
    it('should not throw an error', function() {
     (function() {
      [1,2,3].indexOf(4);
     }).should.not.throw();
    });
    it('should return -1', function() {
     [1,2,3].indexOf(4).should.equal(-1);
    });
   });
   context('when present', function() {
    it('should return the index where the element first appears in the array', function() {
     [1,2,3].indexOf(3).should.equal(2);
    });
   });
  });
 });

TDD - 提供了 suite(), test(), suiteSetup(), suiteTeardown(), setup(), 和 teardown()的函数,其实和BDD风格的接口类似(suite相当于describe,test相当于it),示例代码如下:

suite('Array', function() {
 setup(function() {
  // ...
 });

 suite('#indexOf()', function() {
  test('should return -1 when not present', function() { 
   assert.equal(-1, [1,2,3].indexOf(4));
  });
 });
});

Exports - 对象的值都是测试用例集合,函数值都是测试用例。 关键字before, after, beforeEach, and afterEach 需要特别定义。
具体的示例代码如下:

module.exports = {
 before: function() {
  // ...
 },

 'Array': {
  '#indexOf()': {
   'should return -1 when not present': function() {
    [1,2,3].indexOf(4).should.equal(-1);
   }
  }
 }
};

QUnit - 有点像TDD,用suit和test函数,也包含before(), after(), beforeEach()和afterEach(),但是用法稍微有点不一样, 可以参考下面的代码:

function ok(expr, msg) {
 if (!expr) throw new Error(msg);
}

suite('Array');

test('#length', function() {
 var arr = [1,2,3];
 ok(arr.length == 3);
});

test('#indexOf()', function() {
 var arr = [1,2,3];
 ok(arr.indexOf(1) == 0);
 ok(arr.indexOf(2) == 1);
 ok(arr.indexOf(3) == 2);
});

suite('String');

test('#length', function() {
 ok('foo'.length == 3);
});

Require - 该接口允许我们利用require关键字去重新封装定义 describe ,it等关键字,这样可以避免全局变量。
如下列代码:

var testCase = require('mocha').describe;
var pre = require('mocha').before;
var assertions = require('mocha').it;
var assert = require('assert');

testCase('Array', function() {
 pre(function() {
  // ...
 });

 testCase('#indexOf()', function() {
  assertions('should return -1 when not present', function() {
   assert.equal([1,2,3].indexOf(4), -1);
  });
 });
});

上述默认的接口是BDD, 如果想使用其他的接口,可以使用下面的命令行:

mocha -ui  接口(TDD|Exports|QUnit...)

Reporters (测试报告/结果样式)

Mocha 支持不同格式的测试结果暂时,其支持 Spec, Dot Matrix,Nyan,TAP…等等,默认的样式为Spec,如果需要其他的样式,可以用下列命令行实现:

mocha --reporter 具体的样式(Dot Matrix|TAP|Nyan...)

Editor Plugins

mocha 能很好的集成到TextMate,Wallaby.js,JetBrains(IntelliJ IDEA, WebStorm) 中,这里就用WebStorm作为例子。 JetBrains提供了NodeJS的plugin让我们很好的使用mocha和nodeJs。 添加mocha 的相关的菜单,具体配置过程可以参考https://www.jetbrains.com/webstorm/help/running-mocha-unit-tests.html

这里就可以直接在WebStorm中运行,调试mocha的测试用例了。

NodeJs 相关文章推荐
基于NodeJS的前后端分离的思考与实践(三)轻量级的接口配置建模框架
Sep 26 NodeJs
NodeJS学习笔记之Connect中间件模块(二)
Jan 27 NodeJs
NodeJS学习笔记之Connect中间件应用实例
Jan 27 NodeJs
nodejs连接mongodb数据库实现增删改查
Dec 01 NodeJs
详解Nodejs基于mongoose模块的增删改查的操作
Dec 21 NodeJs
NodeJS仿WebApi路由示例
Feb 28 NodeJs
详谈Angular路由与Nodejs路由的区别
Mar 05 NodeJs
nodejs模块学习之connect解析
Jul 05 NodeJs
解决nodejs的npm命令无反应的问题
May 17 NodeJs
NodeJS 实现多语言的示例代码
Sep 11 NodeJs
nodejs实现获取本地文件夹下图片信息功能示例
Jun 22 NodeJs
用Nodejs实现在终端中炒股的实现
Oct 18 NodeJs
NodeJS测试框架mocha入门教程
Mar 28 #NodeJs
nodejs模块nodemailer基本使用-邮件发送示例(支持附件)
Mar 28 #NodeJs
angular2+nodejs实现图片上传功能
Mar 27 #NodeJs
深入nodejs中流(stream)的理解
Mar 27 #NodeJs
nodejs学习笔记之路由
Mar 27 #NodeJs
NodeJS处理Express中异步错误
Mar 26 #NodeJs
简单好用的nodejs 爬虫框架分享
Mar 26 #NodeJs
You might like
网络资源
2006/10/09 PHP
SSI指令
2006/11/25 PHP
PHP多维数组遍历方法(2种实现方法)
2015/12/10 PHP
thinkphp自定义权限管理之名称判断方法
2017/04/01 PHP
HTML中事件触发列表与解说
2007/07/09 Javascript
jquery $.getJSON()跨域请求
2011/12/21 Javascript
JQuery.closest(),parent(),parents()寻找父结点
2012/02/17 Javascript
jQuery 计算iframe 窗口大小的方法
2014/05/13 Javascript
JavaScript和HTML DOM的区别与联系及Javascript和DOM的关系
2015/11/15 Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
2016/05/04 Javascript
JavaScript 轮播图和自定义滚动条配合鼠标滚轮分享代码贴
2016/10/28 Javascript
使用BootStrap实现表格隔行变色及hover变色并在需要时出现滚动条
2017/01/04 Javascript
简单谈谈Javascript函数中的arguments
2017/02/09 Javascript
layui弹出层效果实现代码
2017/05/19 Javascript
基于zTree树形菜单的使用实例
2017/12/25 Javascript
tangram.js库实现js类的方式实例分析
2018/01/06 Javascript
深入理解Node module模块
2018/03/26 Javascript
[01:48]2018DOTA2亚洲邀请赛主赛事第二日五佳镜头 VG完美团战逆转TNC
2018/04/05 DOTA
python调用cmd命令行制作刷博器
2014/01/13 Python
python保存数据到本地文件的方法
2018/06/23 Python
Python 最大概率法进行汉语切分的方法
2018/12/14 Python
在python Numpy中求向量和矩阵的范数实例
2019/08/26 Python
购买大码女装:Lane Bryant
2016/09/07 全球购物
澳大利亚冲浪和时尚服装网上购物:SurfStitch
2017/07/29 全球购物
美国马匹用品和骑马配件购物网站:Horse.com
2018/01/08 全球购物
中国旅游网站:途牛旅游网
2019/09/29 全球购物
C++面试题目
2013/06/25 面试题
半年思想汇报
2013/12/30 职场文书
办理生育手续介绍信
2014/01/14 职场文书
幼儿教师研修感言
2014/02/12 职场文书
如何写一封打动人心的求职信
2014/02/17 职场文书
预备党员对照检查材料思想汇报
2014/09/24 职场文书
清洁工个人总结
2015/03/04 职场文书
Python预测分词的实现
2021/06/18 Python
如何利用golang运用mysql数据库
2022/03/13 Golang
一篇文章带你掌握SQLite3基本用法
2022/06/14 数据库