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简单实现中英文翻译
May 04 NodeJs
使用Angular和Nodejs、socket.io搭建聊天室及多人聊天室
Aug 21 NodeJs
Nodejs进阶:核心模块net入门学习与实例讲解
Nov 21 NodeJs
nodejs 实现钉钉ISV接入的加密解密方法
Jan 16 NodeJs
NodeJS学习笔记之Module的简介
Mar 24 NodeJs
NodeJS基础API搭建服务器详细过程记录
Apr 01 NodeJs
nodejs mysql 实现分页的方法
Jun 06 NodeJs
nodejs基础之多进程实例详解
Dec 27 NodeJs
nodejs 使用http进行post或get请求的实例(携带cookie)
Jan 03 NodeJs
nodejs对mongodb数据库的增加修删该查实例代码
Jan 05 NodeJs
nodejs+koa2 实现模仿springMVC框架
Oct 21 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
PHP中英混合字符串截取函数代码
2011/07/17 PHP
thinkphp3.0 模板中函数的使用
2012/11/13 PHP
PHP登录环节防止sql注入的方法浅析
2014/06/30 PHP
PHP开发框架kohana中处理ajax请求的例子
2014/07/14 PHP
详解php实现页面静态化原理
2017/06/21 PHP
PHP APP微信提现接口代码
2018/09/30 PHP
php实现二叉树中和为某一值的路径方法
2018/10/14 PHP
Yii2处理密码加密及验证的方法
2019/05/12 PHP
JavaScript的9个陷阱及评点分析
2008/05/16 Javascript
JavaScript日历实现代码
2010/09/12 Javascript
js实现拉伸拖动iframe的具体代码
2013/08/03 Javascript
屏蔽IE弹出"您查看的网页正在试图关闭窗口,是否关闭此窗口"的方法
2013/12/31 Javascript
jQuery实现的图文高亮滚动切换特效实例
2015/08/10 Javascript
JavaScript事件类型中UI事件详解
2016/01/14 Javascript
JS产生随机数的几个用法详解
2016/06/22 Javascript
JavaScript中日期函数的相关操作知识
2016/08/03 Javascript
关于两个jQuery(js)特效冲突的bug的解决办法
2016/09/04 Javascript
使用jquery如何获取时间
2016/10/13 Javascript
weex里Vuex state使用storage持久化详解
2017/09/09 Javascript
Vue实现todolist删除功能
2018/06/26 Javascript
vue中的过滤器实例代码详解
2019/06/06 Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
2019/08/09 Javascript
python实现文件分组复制到不同目录的例子
2014/06/04 Python
用Python将动态GIF图片倒放播放的方法
2016/11/02 Python
Python+matplotlib绘制不同大小和颜色散点图实例
2018/01/19 Python
Python3实现购物车功能
2018/04/18 Python
简单了解django索引的相关知识
2019/07/17 Python
详解python对象之间的交互
2020/09/29 Python
Python入门基础之数字字符串与列表
2021/02/01 Python
德国50岁以上交友网站:Lebensfreunde
2020/03/18 全球购物
linux面试题参考答案(10)
2013/11/04 面试题
领导干部培训感言
2014/01/23 职场文书
党支部公开承诺书
2014/03/28 职场文书
财务统计员岗位职责
2015/04/14 职场文书
医院见习总结
2015/06/24 职场文书
某某店铺的开业庆典主持词范本
2019/11/25 职场文书