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实用示例 缩址还原
Dec 28 NodeJs
nodejs中简单实现Javascript Promise机制的实例
Dec 06 NodeJs
NodeJS制作爬虫全过程
Dec 22 NodeJs
nodejs批量修改文件编码格式
Jan 22 NodeJs
ubuntu下安装nodejs以及升级的办法
May 08 NodeJs
Nodejs实现短信验证码功能
Feb 09 NodeJs
实例分析nodejs模块xml2js解析xml过程中遇到的坑
Mar 18 NodeJs
nodejs和C语言插入mysql数据库乱码问题的解决方法
Apr 14 NodeJs
详解webpack打包nodejs项目(前端代码)
Sep 19 NodeJs
Nodejs模块的调用操作实例分析
Dec 25 NodeJs
深入理解nodejs搭建静态服务器(实现命令行)
Feb 05 NodeJs
如何利用nodejs实现命令行游戏
Nov 24 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调用三种数据库的方法(2)
2006/10/09 PHP
PHP闭包实例解析
2014/09/08 PHP
微信公众号开发之微信公共平台消息回复类实例
2014/11/14 PHP
PHP使用mysqldump命令导出数据库
2015/04/14 PHP
PHP简单生成缩略图相册的方法
2015/07/29 PHP
因str_replace导致的注入问题总结
2019/08/08 PHP
URL编码转换,escape() encodeURI() encodeURIComponent()
2006/12/27 Javascript
jQuery Ajax请求状态管理器打包
2012/05/03 Javascript
javascript使用定时函数实现跳转到某个页面
2013/12/25 Javascript
Javascript之Date对象详解
2016/06/07 Javascript
详解BootStrap中Affix控件的使用及保持布局的美观的方法
2016/07/08 Javascript
微信小程序 实现动态显示和隐藏某个控件
2017/04/27 Javascript
Angular2使用vscode断点调试ts文件的方法
2017/12/13 Javascript
vue select选择框数据变化监听方法
2018/08/24 Javascript
基于Angular中ng-controller父子级嵌套的相关属性详解
2018/10/08 Javascript
vue实现Input输入框模糊查询方法
2021/01/29 Javascript
Python中使用摄像头实现简单的延时摄影技术
2015/03/27 Python
Python定时执行之Timer用法示例
2015/05/27 Python
Python编码类型转换方法详解
2016/07/01 Python
Python 用matplotlib画以时间日期为x轴的图像
2019/08/06 Python
Python代码执行时间测量模块timeit用法解析
2020/07/01 Python
python中not、and和or的优先级与详细用法介绍
2020/11/03 Python
Django中如何用xlwt生成表格的方法步骤
2021/01/31 Python
html5 canvas 画图教程案例分析
2012/11/23 HTML / CSS
Ootori在线按摩椅店:一家专业的按摩椅制造商
2019/04/10 全球购物
中东最大的在线宠物店:Dubai Pet Food
2020/06/11 全球购物
某/etc/fstab文件中的某行如下: /dev/had5 /mnt/dosdata msdos defaults,usrquota 1 2 请解释其含义
2013/04/11 面试题
初中科学教学反思
2014/01/21 职场文书
法学专业自我鉴定
2014/02/05 职场文书
三八妇女节活动主持词
2014/03/17 职场文书
护士长2014年度工作总结
2014/11/11 职场文书
2015年妇女工作总结
2015/05/14 职场文书
给领导敬酒词
2015/08/12 职场文书
详解Django中 render() 函数的使用方法
2021/04/22 Python
python数据可视化使用pyfinance分析证券收益示例详解
2021/11/20 Python
nginx sticky实现基于cookie负载均衡示例详解
2022/12/24 Servers