JS测试之Mocha

Mar 26, 2017


Mocha是一个非常流行的JavaScript 测试框架,可以运行在 Node.js和浏览器中。测试用例的语法与Jasmine类似。测试用例如:

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(4));
    });
  });
});

实际上这个测试用例也完全可以放到jasmine下运行。

Node.js后台运行Mocha测试

安装mocha

npm install -g mocha

当前目录创建test.js文件,文件内容如上举例的测试用例。

mocha . 可以运行测试并看到结果。

mocha默认会从test目录下读取测试文件。

另在npm管理的项目中,可以npm install -D mocha将mocha加到package.json的devDependencies中,并在package.json中设置test如:

"scripts": {
    "test": "mocha ."
}

而后 npm testnpm run test 即可以读取当前目录下的测试文件并执行测试。

Node.js + mocha + chai

Mocha库中没有自己的断言,但是支持使用第三方的断言:node.js自带的断言(assert),expect.js的断言(expect), chai库的(expect, assert, should style), better-asset, unpected. 关于断言,请参考JS测试之断言

下面是使用流行的断言库chai与mocha集成的例子。

  • npm init创建一个项目,会在当前目录生成package.json文件来管理库信息,依赖以及npm脚本。

  • npm install -D mocha chai 安装依赖包mocha以及chai, 并将安装的版本信息写到package.json的devDependencies中。

  • mkdir test && touch test.js 创建测试文件:

    var expect = require('chai').expect;
    describe('Array', function() {
      describe('#indexOf()', function() {
        it('should return -1 when the value is not present', function() {
          expect([1,2,3].indexOf(4)).to.equal(-1);
        });
      });
    });
    
  • 在package.json中设置test任务脚本:

    "scripts": {
        "test": "mocha"
    }
    
  • npm testnpm run test即可以运行测试。

浏览器运行Mocha测试

  • mocha init test/ 在test目录下生成mocha浏览器测试的相关文件index.html, mocha.css, mocha.js以及tests.js.

  • index.html中会调用mocha.run()来运行测试,其文件内容如下:

    <!DOCTYPE html>
    <html>
      <head>
        <title>Mocha</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="mocha.css" />
      </head>
      <body>
        <div id="mocha"></div>
        <script src="mocha.js"></script>
        <script>mocha.setup('bdd');</script>
        <script src="http://chaijs.com/chai.js"></script>
        <script src="tests.js"></script>
        <script>
          mocha.run();
        </script>
      </body>
    </html>
    

    <script src="http://chaijs.com/chai.js"></script> 是手动加上去的,因为在浏览器中需要一个全局的chai.expect对象。

  • 将测试用例放入tests.js中,注意将var expect = require('chai').expect;修改为var expect = chai.expect

  • 浏览器打开index.html,即可看到测试结果。

图1 Mocha浏览器测试结果
图1 Mocha浏览器测试结果

引入babel测试ES6

Node.js中只支持一部分的ES6语法,但是一部分是不支持的。如import关键字。

  • 将测试文件中的var expect = require('chai').expect;修改为import { expect } from 'chai';

  • npm test 将会报错:

    (function (exports, require, module, __filename, __dirname) { import { expect } from 'chai';
                                                                  ^^^^^^
    SyntaxError: Unexpected token import
    ....
    
  • 要解决上一步的问题,需要引入babel, 首先npm install -D babel-core babel-preset-es2015安装babel依赖。

  • 项目目录下创建.babelrc配置文件
    {
      "presets": [ "es2015" ]
    }
    
  • mocha --compilers js:babel-core/register跑测试,测试不会再报异常。

从Babel 6.0开始,不再直接提供浏览器版本,而是要用构建工具构建出来。最好的使用方法是先将代码打包成浏览器可以使用的版本,如使用Babel和Browserify

Mocha异步测试

mocha原生异步测试

mocha为it方法提供了一个回调函数done,如:

describe('#save()', () => {
  it('should save without error', () => {
    var user = new User('Luna');
    user.save((err) => {
      if (err) done(err);
      else done();
    });
  });
});

配置timeout:

it('should take less than 500ms', function(done){
  this.timeout(500);
  setTimeout(done, 300);
});

chai-as-promised异步测试

npm install -D chai-as-promised 安装依赖。

如果引入了chai-as-promised, 测试Promise可以不使用回调函数done, 如:

import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
chai.use(chaiAsPromised);
const expect = chai.expect;

const testPromise = () => Promise.resolve([1, 2, 3]);

describe('#testPromise', function() {
  it('respond with matching records', function() {
    return expect(testPromise()).to.eventually.have.length(3);
  });
});

Mocha常用命令/函数

Mocha常用命令

  • mocha --recursive 测试test子目录下面所有的测试用例。

  • mocha --watch 用来监视测试脚本的变化,每个变化都会重新运行测试。

  • mocha --bail 用来fail fast,即当一个测试用例失败时,就停止执行后面的所有测试。

  • mocha 'test/**/*.@(js|jsx)' 测试指定运行test目录下面任何子目录中、文件后缀名为js或jsx的测试脚本。

  • mocha --reporter [报告样式]可以设置报告样式,其默认值为spec, 也可以设置为tapdot, nyan, list, progress, json等。

Mocha测试用例中常用函数

  • describe, describe.only, describe.skip

  • it, it.only, it.skip

  • before()、after()、beforeEach()和afterEach()

  • 在describe中使用this.retries(4);,设置当测试失败时测试的重复次数,不建议在单元测试中使用

  • 可以在describe中动态生成测试用例,如下代码将生成3个测试

    var expect = require('chai').expect;
    
    function add(array) {
      return array.reduce(function(prev, curr) {
        return prev + curr;
      }, 0);
    }
    
    describe('#add', () => {
      var tests = [
        {args: [1, 2],       expected: 3},
        {args: [1, 2, 3],    expected: 6},
        {args: [1, 2, 3, 4], expected: 10}
      ];
    
      tests.forEach(function(test) {
        it('correctly adds ' + test.args, function() {
          var res = add(test.args);
          expect(res).to.equal(test.expected);
        });
      });
    });
    

参考资料