- Mocha">1. Mocha
- Chai">2. Chai
- istanbul(nyc)">3. istanbul(nyc)
- Sinon">4.Sinon
- Karma">5. Karma
在JavaScript最流行的测试框架中,Mocha(摩卡)一直处于前列,即使背靠Facebook的Jest,也很难大范围对Mocha取而代之,而Mocha之所以流行,很大一部分原因则是由于其和其他框架与工具良好的结合性,而与Mocha配合最好的框架,莫过于Chai(茶),Istanbul
(nyc)(伊斯坦布尔), Sinon和Karma。正是这一批框架的良好结合,才让JavaScript的BDD与TDD无往不利。
1. Mocha
Mocha的官方介绍是简单、灵活而有趣(Simple,
flexible,fun)。是一套可以运行在Nodejs或者浏览器中的JavaScript测试框架。可以提供包括断言、异步、覆盖率报告等各项功能,当然,其中一些功能需要与其他框架配合才能更好地发挥作用。
与其他Nodejs包一样,Mocha可以简单地通过npm(当然也可以通过yarn或者淘宝的cnpm)全局安装或者仅安装在本项目中。以cnpm为例。
#全局安装cnpm install --global mocha#安装在项目开发依赖中cnpm install --save-dev mocha
Mocha默认自动运行test文件夹下的测试文件,因此需要在项目文件夹下新建test文件夹以供测试,如果要将测试命令添加到项目中,需要在项目package.json文件添加:
"scripts": {"test": "mocha"}
Mocha默认支持Nodejs内置的assert模块,不过,如果要使测试更灵活,则需要安装断言库——Chai(茶)便是这些断言库中最流行的。
一段典型的使用内置assert模块的测试代码如下(官方代码):
var assert = require('assert');describe('Array', function() {describe('#indexOf()', function() {it('should return -1 when the value is not present', function() {assert.equal([1, 2, 3].indexOf(4), -1);});});});
2. Chai
Chai(茶)可以说是Mocha的黄金搭档,是一个支持BDD(行为驱动开发)和TDD(测试驱动开发)的断言库,同样可以运行在Node和浏览器环境中。Chai的安装和Mocha类似,而一般来说两者往往也是同时安装的。
Chai支持Should、Expect和Assert三种风格的断言,可以按照个人习惯和喜好选择使用。一段使用了Chai的典型金丝雀(canary)测试代码如下。在实际使用中,金丝雀测试通常是为了确认安装环境没有问题的第一个测试。
var expect=require('chai').expect;describe('Canary tests',()=>{it('should pass the canary test',()=>{expect(true).to.be.true;});});
为了保持测试语言风格的一致性,Chai断言库也有一些扩展库,比如,为了实现在断言测试中保持chai的风格,可以安装chai-as-promised库,为了在karma中使用chai风格断言,可以安装karma-chai-as-promised, 而为了在sinon中使用chai风格断言,则可能需要安装sinon-chai.以cnpm下安装为例。
cnpm install --save-dev chaicnpm install --save-dev chai-as-promisedcnpm install --save-dev karma-chai-as-promisedcnpm install --save-dev sinon-chai
2.1 Chai-as-promised
在没有安装chai-as-promised的情况下,一段用于测试promise的代码可能是这样(官方代码)。
doSomethingAsync().then(
function (result) {
result.should.equal("foo");
done();
},
function (err) {
done(err);
}
);
而安装了chai-as-promised库之后则可能是如下的样子(expect风格)。
var chai=require('chai');
var chaiAsPromised=require('chai-as-promised');
var expect=chai.use(chaiAsPromised).expect;
return expect(doSomethingAsync())to.eventually.eql('foo');
chai-as-promised断言库部分接口扩展如下(expect风格):
return expect(PromiseFn).to.be.fulfilled;
return expect(PromiseFn).to.be.eventually.eql('foo');
return expect(PromiseFn).to.be.rejected;
return expect(PromiseFn).to.be.rejectedWith(Error);
return expect(PromseFn.resolve({'foo':'bar'})).to.eventually.have.property('foo');
expect(PromiseFn).to.be.fulfilled.notify(done);
2.2 Sinon-Chai
一段Sinon-chai官方的测试代码示例如下:
"use strict";
var chai = require("chai");
var sinon = require("sinon");
var sinonChai = require("sinon-chai");
var expect = chai.expect;
chai.use(sinonChai);
function hello(name, cb) {
cb("hello " + name);
}
describe("hello", function () {
it("should call callback with correct greeting", function () {
var cb = sinon.spy();
hello("foo", cb);
expect(cb).to.have.been.calledWith("hello foo");
});
});
3. istanbul(nyc)
istanbul(伊斯坦布尔)是nyc包的曾用名,nyc是一个测试覆盖率工具,可以方便检查代码的测试情况与覆盖率。同样使用npm包安装。
cnpm install --save-dev nyc
安装后,在package包中配置脚本即可直接运行。如果不想覆盖使用mocha的test命令,可以增加一个诸如cov或者coverage的命令,可以在命令行启动
{
"scripts": {
"cov": "nyc mocha"
}
}
nyc也支持配置文件及通过命令扩展输出不同风格的报告。
{
"scripts": {
"cov": "nyc --reporter=html --reporter=text mocha"
}
}
npm run cov
4.Sinon
sinon的名称可能是从法语不然/否则来的,不过这只是猜测,并没有官方的说法。sinon并不是测试框架,却是宣称可以和任何JavaScript测试框架配合的测试库,Sinon的主要作用是提供spies、stubs和mocks功能,用于在测试工程中为被测试代码提供环境。
在BDD或者TDD风格的程序开发中,在测试一段程序时,往往还不存在与其相配合的代码片段(还没有写出来),也没有或者不能使用真实的网络、数据库等进行测试,因此就需要sinon库来进行模拟与仿真,保证待测代码片段运行的上下文,以分段进行代码测试。
在Sinon的几个库中,spies顾名思义,与间谍类似,主要用于监听程序/函数调用过程的信息,通过这些信息验证代码是否正常运行。spies本身并不会影响函数上下文运行环境,因此需要其他几个库的配合;stub的作用是取代某个函数与模块,用于代替原来的函数实现某部分功能,比如一段解析文件内容的函数A,需要另一端打开并读取文件的函数B来提供文件的原始内容,那么在测试A的时候,就可以通过stub函数虚拟出来一个函数B来提供测试内容,这时真实的函数B并不会运行(也可能还没有真正写出来实现),从而做到各个模块(包括模块的特定分支)独立运行和测试;mock模块与stub有一些类似,但又不完全相同,mock模块可以验证某些函数或者模块更具体的功能和行为,比如函数A在异常时会调用函数B,那么通过Mock函数B可以验证B被调用的次数,以及B被调用的次数、包含的参数等等。
为了保证测试的独立性,在sinon中提供了沙盒sandbox模块,通过sandbox模块可以避免测试对项目代码带来污染的可能。而除了上述几个模块外,sinon还提供了faketimer,fake等等实用而强大的模块,模拟真是环境中的setTimeout,setIntervals等延时条件,加快测试进度。
一段官方的sinon测试代码如下,在安装了如前所述的sinon-chai模块后,也可以使用expect或者should风格的测试语句。
const expect=require('chai').expect;
const sinon=require('sinon');
const fs=require('fs');
var Stockfetch=require('../src/stockfetch');
describe('Stockfetch tests',()=>{
let stockfetch;
let sandbox;
beforeEach(()=>{
stockfetch=new Stockfetch();
sandbox=sinon.createSandbox();
})
afterEach(()=>{
sandbox.restore();
})
it('should pass this canary test',()=>{
expect(true).to.be.true;
});
5. Karma
Karma主要用于验证客户端代码的行为,它是一个轻量级的可以用于不同浏览器环境的服务器,安装karma时,可能需要根据情况选择安装和配置不同的插件,比如:
cnpm install --save-dev karma
cnpm install --save-dev karma-mocha
cnpm install --save-dev karma-chai
cnpm install --save-dev karma-chrome-launcher
cnpm install --save-dev karma-firefox-launcher
cnpm install --save-dev karma-clear-screen-reporter
cnpm install --save-dev karma-cli
cnpm install --save-dev karma-coverage
在安装完之后,要对karma进行初始化及配置,运行。
node node_modules/karma/bin/karma init
根据实际情况依次选择测试框架(默认使用jasmine,如果使用了mocha需要修改),浏览器等参数,在初始化完成后,也可以在生成的karma.conf.js文件中修改相应部分内容以修改karma的配置。karma支持自动化监控运行,即只要源代码有所修改,就会自动运行测试程序。
