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开发微博实例
Mar 25 NodeJs
Nodejs Stream 数据流使用手册
Apr 17 NodeJs
Nodejs下用submit提交表单提示cannot post错误的解决方法
Nov 21 NodeJs
nodejs进阶(6)—连接MySQL数据库示例
Jan 07 NodeJs
nodejs搭建本地服务器并访问文件的方法
Mar 03 NodeJs
nodejs个人博客开发第五步 分配数据
Apr 12 NodeJs
nodejs接入阿里大鱼短信验证码的方法
Jul 10 NodeJs
NodeJS爬虫实例之糗事百科
Dec 14 NodeJs
nodejs超出最大的调用栈错误问题
Dec 27 NodeJs
详解nodejs 配置文件处理方案
Jan 02 NodeJs
nodejs对项目下所有空文件夹创建gitkeep的方法
Aug 02 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 expects parameter 1 to be resource, array given 错误
2011/03/23 PHP
浅析PHP中的UNICODE 编码与解码
2013/06/29 PHP
smarty模板引擎从配置文件中获取数据的方法
2015/01/22 PHP
php通过各种函数判断0和空
2020/07/04 PHP
5个javascript的数字格式化函数分享
2011/12/07 Javascript
js完美的div拖拽实例代码
2014/01/22 Javascript
iframe子页面与父页面在同域或不同域下的js通信
2014/05/07 Javascript
js实现按Ctrl+Enter发送效果
2014/09/18 Javascript
jQuery实现按钮的点击 全选/反选 单选框/复选框 文本框 表单验证
2015/06/25 Javascript
JS仿百度自动下拉框模糊匹配提示
2016/07/25 Javascript
zepto与jquery的区别及zepto的不同使用8条小结
2016/07/28 Javascript
Bootstrap图片轮播组件Carousel使用方法详解
2016/10/20 Javascript
JS实现控制图片显示大小的方法【图片等比例缩放功能】
2017/02/18 Javascript
jQuery实现表格奇偶行显示不同背景色 就这么简单
2017/03/13 Javascript
JS原生轮播图的简单实现(推荐)
2017/07/22 Javascript
最通俗易懂的javascript变量提升详解
2017/08/05 Javascript
JavaScript中递归实现的方法及其区别
2017/09/12 Javascript
微信小程序 拍照或从相册选取图片上传代码实例
2019/08/28 Javascript
JavaScript实现烟花绽放动画效果
2020/08/04 Javascript
JavaScript实现多文件下载方法解析
2020/08/07 Javascript
[01:10]DOTA2亚洲邀请赛 征战号角响彻全场
2015/01/06 DOTA
python使用PyGame模块播放声音的方法
2015/05/20 Python
浅谈Python2.6和Python3.0中八进制数字表示的区别
2017/04/28 Python
浅析python继承与多重继承
2018/09/13 Python
Python爬取某平台短视频的方法
2021/02/08 Python
pytho matplotlib工具栏源码探析一之禁用工具栏、默认工具栏和工具栏管理器三种模式的差异
2021/02/25 Python
Java方面的关于数组和继承的笔面试题
2015/09/18 面试题
如何整合JQuery和Prototype
2014/01/31 面试题
应届毕业生求职信
2013/11/30 职场文书
计算机操作自荐信
2013/12/07 职场文书
2014年精神文明建设工作总结
2014/11/19 职场文书
煤矿安全保证书
2015/02/27 职场文书
小学生2015教师节演讲稿
2015/03/19 职场文书
汤姆叔叔的小屋读书笔记
2015/06/30 职场文书
为Java项目添加Redis缓存的方法
2021/05/18 Redis
python数字图像处理之对比度与亮度调整示例
2022/06/28 Python