摩卡,茶,伊斯坦布尔, Sinon 及其他

摩卡,茶,伊斯坦布尔, Sinon 及其他
在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 mochaMocha默认自动运行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 chai cnpm install --save-dev chai-as-promised cnpm install --save-dev karma-chai-as-promised cnpm 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支持自动化监控运行,即只要源代码有所修改,就会自动运行测试程序。


