如何调试 mocha js 单元测试测试用例

Nodejs单元测试小结_小组_ThinkSAAS
Nodejs单元测试小结
Nodejs单元测试小结
最近在写一课程的Project,用Node写了一个实时聊天小应用,其中就用到了单元测试。在写Node单元测试的时候,一方面感受到了单元测试的重要性,另一方面感受到了Node单元测试的不够成熟,尚未有成熟的理论体系,所以想写篇博客探讨一下Node里面单元测试的方法。示例代码部署在Github上面,地址是:,欢迎fork~
单元测试简介
根据维基百科的定义:
在计算机编程中,单元测试(又称为模块测试, Unit Testing)是针对程序模块(软件设计的最小单位)来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。
JavaScript是面向对象编程的,很多时候我们都需要将一个功能掉抽象成一个组件,方便团队其他开发者调用,那么我们就理应保证我们给出的组件是正确可用的。在很长的一段时间里,前端都忽略了单元测试,或者说对于前端这种GUI编程来说,单元测试确实比较麻烦。随着Node的异军突起,针对JavaScript的单元测试框架如雨后春笋,前端也逐渐玩起了单元测试。
单元测试的重要性是不言而喻的,经常存在的一个误区是:
单元测试不是测试人员的事情么?
自己为什么要测试自己的代码?
单元测试的成本这么高对于产品开发有意义么?
我这么牛我不需要单元测试!
上面的几点也是我之前怀疑过的,但是觉得现在每一点都是不容置疑的。首先,认为测试是测试人员的事情是不负责的,测试人员更多的应该是针对整体功能,而每一位工程师应该保证自己代码的准确性;其次自己测试自己的代码更多的时候是为了提高效率。如果我写好了一个接口,没有经过测试就直接交给了别人,那么出错之后就需要接着调试,其中所花费的沟通成本会大大大于编码成本,这也顺带解决了第三个疑问;最后,在Github上面所有star过万的repo都应该有自己的测试,我相信这些repo的作者比大部分人都牛,他们都需要不断测试,我们没有理由不去测试。
单元测试的分类
单元测试根据主流的分类可以分成两类,分别是BDD和TDD
TDD的英文全称是Test-Driven Development,即测试驱动开发。测试驱动开发的流程是
- 开发人员写了一些测试代码
- 开发人员跑了这些测试用例,然后毫无疑问的这些测试用例失败了因为测试中提到的类和方法并没有实现
- 开发人员开始实现测试用例里面提到的方法
- 如果开发者写好了某个功能点,他会欣喜地发现之前的相对应的测试用例通过了
- 开发者人员可以重构代码,并添加注释,完成后期工作
这个流程如下图:
BDD的英文全称是Behavior-Driven Development,即行为驱动开发。
BDD与TDD的主要区别是在写测试案例的时候的措辞,BDD的测试案例更像是一份说明书,在详细描述软件的每一个功能。个人比较喜欢BDD,后续的Demo也是BDD形式的。
关于BDD和TDD的差别可以看看这篇文章:
mocha框架简介
说到JavaScript的测试框架,就不得不提起大名鼎鼎的TJ Holowaychuk写的Mocha了。
Mocha是一个基于node.js和浏览器的集合各种特性的Javascript测试框架,并且可以让异步测试也变的简单和有趣。Mocha的测试是连续的,在正确的测试条件中遇到未捕获的异常时,会给出灵活且准确的报告。
npm install -g mocha
$ 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));
? 1 test complete (1ms)
为了顺利进行单元测试,通常都是组合几种工具来使用的,这里介绍常用的几种。
should 是一个表述性、可读性很强的测试无关的“断言”库。它是BDD风格的,用一个单例的不可枚举的属性访问器扩展了Object的prototype,允许你表述对象应该展示的行为。
node本身有自己的断言模块,但是should所具有的表述性和可读性让开发者没有理由拒绝这么棒的工具。
常用的断言库还有和,这里不再多说
在用Node做Web开发的时候,模拟HTTP请求时必不可少的,如果都需要用浏览器来实现请求,那就太Low了!
supertest是一个非常棒的适用于node的模拟HTTP请求的库,有点拗口,但是看看dmeo就会米桑她优雅的链式写法
var request = require('supertest')
, express = require('express');
var app = express();
app.get('/user', function(req, res){
res.send(200, { name: 'tobi' });
request(app)
.get('/user')
.expect('Content-Type', /json/)
.expect('Content-Length', '20')
.expect(200)
.end(function(err, res){
为了能够展示测试的核心点,又能具有实战性,我们写一个非常简单的demo,这个demo有两个主要功能-注册登录和发布简单的话题
示例代码托管在Github上面,地址是:
示例代码采用nodejs的express框架写了一个非常简单的只有后台的项目。为了demo应有的简介特性,省去了很多应当有的逻辑,力求展示测试过程中应当注意的点。
├── controllers // 控制层
| ├── site.js // 注册登录控制
| └── topic.js // 话题控制
├── models // 数据模型
| ├── index.js // 出口文件
| ├── topic.js // 话题模型
| └── user.js // 用户模型
├── proxy // 数据控制层
| ├── topic.js // 话题数据控制
| └── user.js // 用户数据控制
├── tests // 单元测试
| ├── support/support.js // 模拟数据
| ├── user.test.js // 注册登录控制测试
| └── topic.test.js // 话题控制测试
├── app.js // 项目主文件
├── consig.js // 项目配置文件
├── package.json // 包文件
└── router.js // 路由配置
1. 异步操作的测试
异步无阻塞I/O是Node的灵魂所在,因为用node开发的应用程序处处体现着异步的用法。在编写测试案例的时候,我们的测试代码怎么才能知道测试结果出来了呢?
强大的Mocha自然会考虑到这一点。只需要在你的测试结束时调用回调函数即可。通过给it()添加回调函数(通常命名为done)可以告知Mocha需要等待异步测试结束。这里直接调用官网的例子:
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(done);
2. 具备正反测试用例
测试的一个重要环节就是要提高测试覆盖率。话句话说,你在写代码的时候考虑到的异常情况,在写测试案例的时候也应该考虑在内,也就是所谓的正反测试案例。
describe('sign up', function() {
it('should not sign up an user when loginname is empty', function(done) {
request.post('/signup')
loginname: '',
password: password
.expect(200, function(err, res) {
should.not.exist(err);
res.text.should.containEql('用户名或密码不能为空');
it('should not sign up an user when it is exist', function(done) {
request.post('/signup')
loginname: loginname,
password: password
.expect(200, function(err, res) {
should.not.exist(err);
res.text.should.containEql('用户已经存在');
在写注册登录的测试案例的时候,我们除了希望看到用户名和密码都正确填写的情况下得到测试通过的结果,还希望看到我们故意不输入用户名的时候也能得到正确的"错误提示"。
3. 需要cookie和session的测试案例
在web开发中,Cookie有着非常重要的作用。因为HTTP是无状态的,所以需要用cookie来辅助实现用户认证。我们先来简单介绍一下cookie的工作机制。
如果所示,如果通过cookie和session协同识别一个用户需要两次请求,第一次请求的时候,服务器并不认识你,但是他给你标记了一个他独有的id,等到第二次请求的时候,浏览器自动给你带上了之前的标签,这样服务器就知道你之前请求过了。
那么问题来了,如果我们写测试案例的时候,需要两次请求来实现的话,会非常麻烦,测试案例也会很冗长。怎么才能一次请求就能使用cookie和session呢?
这时候express的中间件的好处就体现了。
首先,我们在用supertest进行HTTP请求的时候,可以通过下面的形式设置cookie:
set('Cookie', cookieValue)
然后,我们写一个非常简单的中间件:
app.use(function(req, res, next) {
if (config.debug && req.cookies['mock_user']) {
var mockUser = JSON.parse(req.cookies['mock_user']);
req.session.user = new UserModel(mockUser);
return next();
原理就是先判断当前是否为开发环境,通过config来设置,通常在开发阶段这个值设置为true。其次判断是否具有键为mock_user的cookie键值对,如果存在,设置session里面的user值,这样,只要一次请求我们就能实现用户标识。
最后要解决的问题就是怎么设置字段键为mock_user的cookie了,具体的用法可参照test目录里面的support/support.js,这里不多说。
4. 测试覆盖率
为了检验自己的测试用例是否全面,我们需要知道自己的测试覆盖率是多少。这里介绍一个与mocha非常有好的istanbul。由于本人是在windows下面写的测试代码,就不写Makefile了,比较蛋疼。之所以强调Windows是因为在Windows运行istanbul的时候会会出现问题,具体见
因此在Windows运行的时候需要像下面这样运行:
./node_modules/.bin/istanbul cover ./node_modules/mocha/bin/_mocha*
最后也不说什么了,附上本地运行示例代码的测试结果和测试覆盖率结果:
PHP开发框架
服务器环境
ThinkSAAS商业授权:
ThinkSAAS为用户提供有偿个性定制开发服务
ThinkSAAS将为商业授权用户提供二次开发指导和技术支持
手机客户端
ThinkSAAS接收任何功能的Iphone(IOS)和Android手机的客户端定制开发服务
官方1群:【已满】
让ThinkSAAS更好,把建议拿来。酷勤网 C 程序员的那点事!
当前位置: >
浏览次数:次
mocha 是一个javascript的测试框架,chai是一个断言库,两者搭配使用更佳,所以合称&抹茶&(其实mocha是咖啡)。&抹茶&特点是: 简单,Hour级学习成本,node和浏览器都可运行,有趣。
关于吹水,充字数的内容我放到了blog最后,因为&抹茶&上手非常的简单,看完blog再阅览一下官网就可以实际动手敲代码了,不足一个小时就可以基本掌握他们了。
Mocha 是一个功能丰富的JavaScript测试框架,他可以跑在node和浏览器上,使异步测试变得简单和有趣。Mocha在运行测试用例过程中,当捕获到错误时,依旧能够灵活地运行精确的报告。
Chai 断言库
Chai是一个BDD/TDD模式的断言库,可以再node和浏览器环境运行,可以高效的和任何js测试框架搭配使用。
BDD,行为驱动开发(注重测试逻辑),TDD是测试驱动开发(注重输出结果)。我们这里的例子都以使用BDD,想扩展这方面知识同学可以搜索更多资料查阅。
二者都可以运行在node和浏览器上,所以后台node单元测试,和前端逻辑js(甚至测试css显示)都可以使用。
在node环境上安装使用
这是官网上的一段示例代码
JavaScript
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));
如果我们的测试文件名字为test.js,运行mocha就
上面的代码有三个陌生的方法,也正是这三个基本方法构成mocha测试框架的基本使用方式。
describe(moduleName, function)
顾名思义,描述一句测试用例是否正确。首先describe是可以嵌套的,多个describe嵌套的使用用于描述模块下的子模块的关系,上面的代码的意思就是测试Array这个类下面的#indexOf()方法, moduleName是可以随便定义的,即是是中文也可以。 &#&的使用也是一般约定,不喜欢你也会换个或不用也可以。
it(info, function)
真正的测试语句是在it函数的function里面,info也是一句描述性的说明,看得懂就行。function里面的断言决定这条测试是否正确。如果fail的话控制台会把log打印出来。一个it对应一个测试用例,里面可以有多条断言或一条断言。
assert.equal(exp1,exp2)
mocha的断言语句,exp1是否等于exp2. 其他更多用法可以查考mocha的文档,但是这里一般我们使用chai来作为断言库。更加友好的实现我们的断言方式。
异步代码测试
上面的官方例子是同步的代码测试,下面看看异步代码如何测试
JavaScript
describe('User', function(){
describe('#save()', function(){
it('should save without error', function(done){
var user = new User('Luna');
user.save(done);
user.save()是要链接数据库,是个异步操作。
跟第一段代码不同,使用了done。done表示你回调的最深处,也是嵌套回调函数的末端。done()函数如果接受一个error的callback,这句测试为fail。
注意一个it里面应该只能有一个done,如果非要有两个异步分叉,那建议用两个it。
before(), after(),beforeEach(),afterEach()
介绍了异步的单元测试,还有一些列方便的辅助方法,方法非常简单明了,我贴个代码出来,大家看看就知道什么意思了。
JavaScript
describe('Connection', function(){
var db = new Connection
, tobi = new User('tobi')
, loki = new User('loki')
, jane = new User('jane');
beforeEach(function(done){
db.clear(function(err){
if (err) return done(err);
db.save([tobi, loki, jane], done);
describe('#find()', function(){
it('respond with matching records', function(done){
db.find({ type: 'User' }, function(err, res){
if (err) return done(err);
res.should.have.length(3);
JavaScript
describe('Array', function(){
describe('#indexOf()', function(){
it('should return -1 when the value is not present', function(){
就是it里面的function留空。mocha默认会pass这条测试。这样的用法其实相当于,某项目负责人定义好了要测试什么内容,之后由相应的开发去实现具体。
only 和skip
JavaScript
describe('Array', function(){
describe('#indexOf()', function(){
it.only('should return -1 unless present', function(){
it('should return the index when present', function(){
使用了only之后,这条descibe就只执行only,其他的忽略。skip作用相反,其他会执行,自己会被忽略。两者一起,自己想想都知道。
mocha这个测试框架大体都介绍得差不多,最后你会惊奇的发现!!! 控制台输出的内容好丑啊!!为什么??为什么?因为你是个没有Mac的死穷吊!
如果想输出测试结果好看点,可以-R 指令来选择一些输出样式。个人建议这样运行【mocha -R spec yourFile】(为什么我知道?不要说了,泪水啊~~)
上面说的都是mocha的测试框架,我们是不是漏了Chai,结合Chai非常非常的简单。
chai这里我们只介绍BDD模式的should风格。来看一段官网代码
JavaScript
var should = require('chai').should()
, foo = 'bar'
, beverages = { tea: [ 'chai', 'matcha', 'oolong' ] };
foo.should.be.a('string');
foo.should.equal('bar');
foo.should.have.length(3);
beverages.should.have.property('tea').with.length(3);
should的风格非常接近自然语言。bizai.should.be.a(&HandsomeBody&) = bizai 应该是个帅哥。
这样的should断言风格去代替mocha的 assert。这样两个结合起来,更加友好和方便。
should.exist
should.not.exist
should.equal
should.not.equal
should.Throw
should.not.Throw
剩下需要扩展学习的可以去官网详细学习。
浏览器上使用&抹茶&
首先需要下载mocha.js,chai.js,mocha.css三个文件。
把三者引入,进行一些设置, 看代码即可。
&!doctype html&
&html lang=&en&&
&meta charset=&UTF-8&&
&title&Unit Testing with Mocha and Chai&/title&
&link rel=&stylesheet& href=&lib/mocha.css&&
&script src=&lib/mocha.js&&&/script&
&script&mocha.setup('bdd'); //设置单元测试模式为BDD模式 &/script&
&script src=&lib/chai.js&&&/script&
&script&chai.Should(); //设置断言模式为 Should模式 &/script&
&div id=&mocha&&&/div&
describe('My first Unit Test',function(){
before(function(){
console.log('AAAAAAAa')
it('should return true for array',function(){
var a = [],b = {};
(a instanceof Array).should.equal(true);
(typeof b == 'object').should.equal(true);
it('should pending when the value is not present',function(){
it('should pending when the value is undfined');
//或者...root级别的hooks..在全局状态下..每次的测试用例都执行了(以it为单位)..
beforeEach(function(){
console.log('before every test');
mocha.run(); // 注意不要漏了这个,在js最后启动mocha
Javascript单元测试,我们真的需要吗?
单元测试,又名模块测试,是开发者在开发过程中,对项目中某个单元模块内部逻辑的检验。这在后台开发中颇为常见,但是在前端领域较为少见。如果我告诉你单元测试什么什么优点啊,你肯定第一时间反驳的第一句就是&花时间写这玩意,有必要吗?&基于web的特性就是快速迭代,一个项目需求时间往往都是快速的,完全没有多余的时间给你去写测试用例,但对于大型的或者需求变更频繁的项目,单元测试就能体验出他的价值。
&怎么单元测试写起来这么麻烦&
&- 说明项目模块之间存在耦合度高,依赖性强的问题。
&怎么要写这么长的测试代码啊&
&- 这是一劳永逸的,并且每次需求变更后,你都可通过单元测试来验证,逻辑代码是否依旧正确。
&我的模块没问题的,是你的模块出了问题&
&- 程序中每一项功能我们都用测试来验证的它的正确性,快速定位出现问题的某一环。
&上次修复的bug怎么又出现了 &
& 单元测试能够避免代码出现回归,编写完成后,可快速运行测试。
接触&抹茶&的起因是项目驱动需要写些单元测试用例,knight大哥推荐了Mocha和Chai 组合来实现我们单元测试的需求。Javascripte单元测试工具比较著名的还有Qunit,JsUnit,JsTestDriver等等,笔者也是刚刚接触,上面的也是基础学习的分享,不敢乱下定论哪款框架好,花时间去研究哪款框架好用,不如试试&抹茶&这种Hour级的学习成本,值得你们尝试学习。
& 相关主题:
本文来源:您的位置:
→ JS测试框架(Mochajs) v1.0 官方版
JS测试框架(Mochajs) v1.0 官方版Mochajs最新免费版下载|
网友评分:8
软件大小:171KB
软件语言:英文
软件类型:国外软件
软件类别:免费软件 / 编程辅助
更新时间:
软件等级:
官方网站:
运行环境:WinAll, WinXP
软件厂商:
顶好评:50%
同类相关软件
778KB/中文/10.022.4M/中文/5.05.7M/中文/10.0113KB/英文/10.04.7M/中文/10.0
JS测试框架(Mochajs)是一款灵活有趣的 JavaScript专业框架测试工具。主要用于 Node.js 和上的 JavaScript 应用测试。它使用起来也是十分方便,而且具有丰富特性的 JavaScript 测试框架,可以运行在 Node.js 和浏览器中,使得异步测试更简单更有趣。赶快下载吧!!!!Mochajs功能特色浏览器的支持简单的异步支持,包括承诺测试覆盖率报告字符串比较支持JavaScript API运行测试CI支持等适当的退出状态自动检测和禁用着色非TTY映射到正确的测试用例未捕获的异常异步测试超时支持测试特定的超时咆哮的通知支持报告的试验时间集锦慢测试文件监视器支持全局变量泄漏检测可选的运行相匹配的正则表达式测试自动退出防止“挂”与有源环路容易产生测试用例元套房mocha.opts支持文件点击标题过滤器执行测试套件节点的调试支持检测到多个电话done()使用你想要的任何断言库可扩展的报告,捆绑9 +记者可扩展的测试DSL或“接口”前,后,前,后各钩transpiler支持任意(咖啡脚本等)Mochajs 命令参数教程命令行参数Usage: mocha [debug] [options] [files]Commands:init &path&initialize a client-side mocha setup at &path&Options:-h, --help & & & & & & & & 输出用法信息-V, --version & & & & & & & & 输出版本号-r, --require &name& & & & & 加载指定的模块-R, --reporter &name& & & & & 指定使用的监控器-u, --ui &name& & & & & & & & & 指定使用的接口(bdd | tdd | exports)-g, --grep &pattern& & & & & 只执行满足路径模式的测试脚本-i, --invert & & & & & & & & inverts --grep matches-t, --timeout &ms& & & & & 设置测试用例的超时时间,单位毫秒,默认为2000-s, --slow &ms& & & & & & & & & &slow& test threshold in milliseconds [75]-w, --watch & & & & & & & & 监测有变化的文件-c, --colors & & & & & & & & 强制使用文本颜色-C, --no-colors & & & & & & & & 强制关闭文本颜色-G, --growl & & & & & & & & enable growl notification support-d, --debug & & & & & & & & enable node's debugger, synonym for node --debug-b, --bail & & & & & & & & bail after first test failure-A, --async-only & & & & & & & &force all tests to take a callback (async)--recursive & & & & & & & & 包含子文件夹--debug-brk & & & & & & & & enable node's debugger breaking on the first line--globals &names& & & & & allow the given comma-delimited global [names]--check-leaks & & & & & & & & check for global variable leaks--interfaces & & & & & & & & 显示可用的接口列表--reporters & & & & & & & & 显示可用的监控器列表--compilers &ext&:&module&,... use the given module(s) to compile filesMochajs使用说明w,――看执行测试对CWD的JavaScript的变化,一旦开始。――编译器咖啡剧本不再支持开箱。CS和类似transpilers 可以通过映射文件扩展名使用(使用――手表)和模块 名称。例如――咖啡:咖啡脚本编译器coffeescript 1.6或以咖啡:咖啡――编译器脚本/注册coffeescript 1.7 +与。B,――保释在第一个例外只感兴趣?使用――保释!D,――调试使节点的调试支持,该执行你的脚本(S)与节点调试&文件……&你可以通过代码和打破的调试器声明。请注意区别摩卡调试和摩卡――调试:摩卡调试会火起来的节点内置的调试客户端,摩卡――调试将允许你使用一个不同的界面如眨眼的开发工具。――全局&名称&接受一个逗号分隔的接受全局变量名列表。例如,假设您的应用程序的全局命名有意暴露应用程序和小唯,你可能想添加――全局应用,YUI。它也接受通配符。你能做的――全局“*酒吧”它将匹配foobar,鲍伯,等你也可以通过在“*”忽略所有的全局变量。――检查泄漏默认情况下,摩卡不会检查全局变量泄露而运行的测试,以使这一关――检查泄漏指定的全局变量,也可以使用――全局,例如――全局jQuery,mylib。R,――需要&名称&的――要求选项是有用的库,如should.js,所以你可能只是――要求应而不是手动调用要求(“应该”)在每个测试文件。注意,这个效果很好应因为它巩固object.prototype然而,如果你想访问一个模块的出口,你会需要它们,例如VaR应要求(=“应该”)。U,――UI &名称&的――UI选项允许您指定要使用的接口,违约“BDD”。R,――记者&名称&的――记者选项允许你指定的记者,将使用缺省的“点”。这个标志也可以利用第三方记者。例如,如果你NPM安装摩卡lcov记者然后你可以做――记者摩卡lcov记者。T,――超时指定测试用例超时,不到2秒。你可以通过重写毫秒超时,或与一个值S后缀,前:――超时2S或――超时2000将等效。S,――慢指定“慢”测试阈值,缺省75ms。摩卡使用这个突出的测试用例,时间太长。G,――grep &模式&的――grep选项时,指定将触发摩卡只运行匹配给定的试验模式这是内部编译到正则表达式。假设比如你有“API”相关的测试,以及“应用程序”相关的测试,如下面的代码段显示;可以使用――grep API或――grep程序运行一个或另一个。同样的一套测试用例名称或任何其他部分,――grep用户将有效的为好,甚至――grep得到。
其他版本下载
JS测试框架(Mochajs) v1.0 官方版
软件无法下载或下载后无法使用,请点击报错,谢谢!
请描述您所遇到的错误,我们将尽快予以修正,谢谢!
*必填项,请输入内容
本类下载排行
10.01 10.02 10.03 10.04 10.05 10.06 10.07 10.08 10.09 10.010 10.011 10.012 10.013 10.014 10.015
本类精品软件
装机必备软件
本类集合软件测试框架 Mocha 实例教程 - 阮一峰的网络日志
测试框架 Mocha 实例教程
(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。
所谓"测试框架",就是运行测试的工具。通过它,可以为JavaScript应用添加测试,从而保证代码的质量。
本文全面介绍如何使用Mocha,让你轻松上手。如果你以前对测试一无所知,本文也可以当作JavaScript单元测试入门。值得说明的是,除了Mocha以外,类似的测试框架还有、、等,也很值得学习。
我为本文写了一个示例库,请先安装这个库。
$ git clone /ruanyf/mocha-demos.git
如果你的电脑没装Git,可以直接下载,进行解压。
然后,进入目录,安装依赖(你的电脑必须有Node)。
$ cd mocha-demos
$ npm install
上面代码会在目录内部安装Mocha,为了操作的方便,请在全面环境也安装一下Mocha。
$ npm install --global mocha
二、测试脚本的写法
Mocha的作用是运行测试脚本,首先必须学会写测试脚本。所谓"测试脚本",就是用来测试源码的脚本。
下面是一个加法模块的代码。
function add(x, y) {
return x +
module.exports =
要测试这个加法模块是否正确,就要写测试脚本。
通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js(表示测试)或者.spec.js(表示规格)。比如,add.js的测试脚本名字就是。
// add.test.js
var add = require('./add.js');
var expect = require('chai').
describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
上面这段代码,就是测试脚本,它可以独立执行。测试脚本里面应该包括一个或多个describe块,每个describe块应该包括一个或多个it块。
describe块称为"测试套件"(test suite),表示一组相关的测试。它是一个函数,第一个参数是测试套件的名称("加法函数的测试"),第二个参数是一个实际执行的函数。
it块称为"测试用例"(test case),表示一个单独的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1 加 1 应该等于 2"),第二个参数是一个实际执行的函数。
三、断言库的用法
上面的测试脚本里面,有一句断言。
expect(add(1, 1)).to.be.equal(2);
所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用add(1, 1),结果应该等于2。
所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。
var expect = require('chai').
断言库有很多种,Mocha并不限制使用哪一种。上面代码引入的断言库是,并且指定使用它的断言风格。
expect断言的优点是很接近自然语言,下面是一些例子。
// 相等或不相等
expect(4 + 5).to.be.equal(9);
expect(4 + 5).to.be.not.equal(10);
expect(foo).to.be.deep.equal({ bar: 'baz' });
// 布尔值为true
expect('everthing').to.be.
expect(false).to.not.be.
expect('test').to.be.a('string');
expect({ foo: 'bar' }).to.be.an('object');
expect(foo).to.be.an.instanceof(Foo);
// include
expect([1,2,3]).to.include(2);
expect('foobar').to.contain('foo');
expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
expect([]).to.be.
expect('').to.be.
expect({}).to.be.
expect('foobar').to.match(/^foo/);
基本上,expect断言的写法都是一样的。头部是expect方法,尾部是断言方法,比如equal、a/an、ok、match等。两者之间使用to或to.be连接。
如果expect断言不成立,就会抛出一个错误。事实上,只要不抛出错误,测试用例就算通过。
it('1 加 1 应该等于 2', function() {});
上面的这个测试用例,内部没有任何代码,由于没有抛出了错误,所以还是会通过。
四、Mocha的基本用法
有了测试脚本以后,就可以用Mocha运行它。请进入子目录,执行下面的命令。
$ mocha add.test.js
加法函数的测试
? 1 加 1 应该等于 2
1 passing (8ms)
上面的运行结果表示,测试脚本通过了测试,一共只有1个测试用例,耗时是8毫秒。
mocha命令后面紧跟测试脚本的路径和文件名,可以指定多个测试脚本。
$ mocha file1 file2 file3
Mocha默认运行test子目录里面的测试脚本。所以,一般都会把测试脚本放在test目录里面,然后执行mocha就不需要参数了。请进入子目录,运行下面的命令。
加法函数的测试
? 1 加 1 应该等于 2
? 任何数加0应该等于自身
2 passing (9ms)
这时可以看到,test子目录里面的测试脚本执行了。但是,你打开test子目录,会发现下面还有一个test/dir子目录,里面还有一个测试脚本,并没有得到执行。原来,Mocha默认只执行test子目录下面第一层的测试用例,不会执行更下层的用例。
为了改变这种行为,就必须加上--recursive参数,这时test子目录下面所有的测试用例----不管在哪一层----都会执行。
$ mocha --recursive
加法函数的测试
? 1 加 1 应该等于 2
? 任何数加0应该等于自身
乘法函数的测试
? 1 乘 1 应该等于 1
3 passing (9ms)
五、通配符
命令行指定测试脚本时,可以使用通配符,同时指定多个文件。
$ mocha spec/{my,awesome}.js
$ mocha test/unit/*.js
上面的第一行命令,指定执行spec目录下面的my.js和awesome.js。第二行命令,指定执行test/unit目录下面的所有js文件。
除了使用Shell通配符,还可以使用Node通配符。
$ mocha 'test/**/*.@(js|jsx)'
上面代码指定运行test目录下面任何子目录中、文件后缀名为js或jsx的测试脚本。注意,Node的通配符要放在单引号之中,否则星号(*)会先被Shell解释。
上面这行Node通配符,如果改用Shell通配符,要写成下面这样。
$ mocha test/{,**/}*.{js,jsx}
六、命令行参数
除了前面介绍的--recursive,Mocha还可以加上其他命令行参数。请在子目录里面,运行下面的命令,查看效果。
6.1 --help, -h
--help或-h参数,用来查看Mocha的所有命令行参数。
$ mocha --help
6.2 --reporter, -R
--reporter参数用来指定测试报告的格式,默认是spec格式。
$ mocha --reporter spec
除了spec格式,官方网站还提供了其他许多。
$ mocha --reporter tap
ok 1 加法函数的测试 1 加 1 应该等于 2
ok 2 加法函数的测试 任何数加0应该等于自身
上面是tap格式报告的显示结果。
--reporters参数可以显示所有内置的报告格式。
$ mocha --reporters
使用模块,可以生成漂亮的HTML格式的报告。
$ npm install --save-dev mochawesome
$ ../node_modules/.bin/mocha --reporter mochawesome
上面代码中,mocha命令使用了项目内安装的版本,而不是全局安装的版本,因为mochawesome模块是安装在项目内的。
然后,测试结果报告就在子目录生成。
6.3 --growl, -G
打开参数,就会将测试结果在桌面显示。
$ mocha --growl
6.4 --watch,-w
--watch参数用来监视指定的测试脚本。只要测试脚本有变化,就会自动运行Mocha。
$ mocha --watch
上面命令执行以后,并不会退出。你可以另外打开一个终端窗口,修改test目录下面的测试脚本add.test.js,比如删除一个测试用例,一旦保存,Mocha就会再次自动运行。
6.5 --bail, -b
--bail参数指定只要有一个测试用例没有通过,就停止执行后面的测试用例。这对很有用。
$ mocha --bail
6.6 --grep, -g
--grep参数用于搜索测试用例的名称(即it块的第一个参数),然后只执行匹配的测试用例。
$ mocha --grep "1 加 1"
上面代码只测试名称中包含"1 加 1"的测试用例。
6.7 --invert, -i
--invert参数表示只运行不符合条件的测试脚本,必须与--grep参数配合使用。
$ mocha --grep "1 加 1" --invert
七,配置文件mocha.opts
Mocha允许在test目录下面,放置配置文件mocha.opts,把命令行参数写在里面。请先进入目录,运行下面的命令。
$ mocha --recursive --reporter tap --growl
上面这个命令有三个参数--recursive、--reporter tap、--growl。
然后,把这三个参数写入test目录下的文件。
--reporter tap
--recursive
然后,执行mocha就能取得与第一行命令一样的效果。
如果测试用例不是存放在test子目录,可以在mocha.opts写入以下内容。
server-tests
--recursive
上面代码指定运行server-tests目录及其子目录之中的测试脚本。
八、ES6测试
如果测试脚本是用ES6写的,那么运行测试之前,需要先用Babel转码。进入目录,打开文件,可以看到这个测试用例是用ES6写的。
import add from '../src/add.js';
import chai from 'chai';
let expect = chai.
describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
ES6转码,需要安装Babel。
$ npm install babel-core babel-preset-es2015 --save-dev
然后,在项目目录下面,新建一个配置文件。
"presets": [ "es2015" ]
最后,使用--compilers参数指定测试脚本的转码器。
$ ../node_modules/mocha/bin/mocha --compilers js:babel-core/register
上面代码中,--compilers参数后面紧跟一个用冒号分隔的字符串,冒号左边是文件的后缀名,右边是用来处理这一类文件的模块名。上面代码表示,运行测试之前,先用babel-core/register模块,处理一下.js文件。由于这里的转码器安装在项目内,所以要使用项目内安装的Mocha;如果转码器安装在全局,就可以使用全局的Mocha。
下面是另外一个例子,使用Mocha测试CoffeeScript脚本。测试之前,先将.coffee文件转成.js文件。
$ mocha --compilers coffee:coffee-script/register
注意,Babel默认不会对Iterator、Generator、Promise、Map、Set等全局对象,以及一些全局对象的方法(比如Object.assign)转码。如果你想要对这些对象转码,就要安装babel-polyfill。
$ npm install babel-polyfill --save
然后,在你的脚本头部加上一行。
import 'babel-polyfill'
九、异步测试
Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。对于涉及异步操作的测试用例,这个时间往往是不够的,需要用-t或--timeout参数指定超时门槛。
进入子目录,打开测试脚本。
it('测试应该5000毫秒后结束', function(done) {
var f = function() {
expect(x).to.be.not.
done(); // 通知Mocha测试结束
setTimeout(f, 4000);
上面的测试用例,需要4000毫秒之后,才有运行结果。所以,需要用-t或--timeout参数,改变默认的超时设置。
$ mocha -t 5000 timeout.test.js
上面命令将测试的超时时限指定为5000毫秒。
另外,上面的测试用例里面,有一个done函数。it块执行的时候,传入一个done参数,当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。否则,Mocha就无法知道,测试是否结束,会一直等到超时报错。你可以把这行删除试试看。
Mocha默认会高亮显示超过75毫秒的测试用例,可以用-s或--slow调整这个参数。
$ mocha -t 5000 -s 1000 timeout.test.js
上面命令指定高亮显示耗时超过1000毫秒的测试用例。
下面是另外一个异步测试的例子。
it('异步请求应该返回一个对象', function(done){
.end(function(err, res){
expect(res).to.be.an('object');
运行下面命令,可以看到这个测试会通过。
$ mocha -t 10000 async.test.js
另外,Mocha内置对Promise的支持,允许直接返回Promise,等到它的状态改变,再执行断言,而不用显式调用done方法。请看。
it('异步请求应该返回一个对象', function() {
return fetch('')
.then(function(res) {
return res.json();
}).then(function(json) {
expect(json).to.be.an('object');
十、测试用例的钩子
Mocha在describe块之中,提供测试用例的四个钩子:before()、after()、beforeEach()和afterEach()。它们会在指定时间执行。
describe('hooks', function() {
before(function() {
// 在本区块的所有测试用例之前执行
after(function() {
// 在本区块的所有测试用例之后执行
beforeEach(function() {
// 在本区块的每个测试用例之前执行
afterEach(function() {
// 在本区块的每个测试用例之后执行
// test cases
进入子目录,可以看到下面两个例子。首先是beforeEach的例子。
// beforeEach.test.js
describe('beforeEach示例', function() {
beforeEach(function() {
it('修改全局变量应该成功', function() {
expect(foo).to.be.equal(true);
上面代码中,beforeEach会在it之前执行,所以会修改全局变量。
另一个例子则是演示,如何在beforeEach之中使用异步操作。
// beforeEach-async.test.js
describe('异步 beforeEach 示例', function() {
beforeEach(function(done) {
setTimeout(function() {
it('全局变量异步修改应该成功', function() {
expect(foo).to.be.equal(true);
十一、测试用例管理
大型项目有很多测试用例。有时,我们希望只运行其中的几个,这时可以用only方法。describe块和it块都允许调用only方法,表示只运行某个测试套件或测试用例。
进入子目录,测试脚本就使用了only。
it.only('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
it('任何数加0应该等于自身', function() {
expect(add(1, 0)).to.be.equal(1);
上面代码中,只有带有only方法的测试用例会运行。
$ mocha test/add.test.js
加法函数的测试
? 1 加 1 应该等于 2
1 passing (10ms)
此外,还有skip方法,表示跳过指定的测试套件或测试用例。
it.skip('任何数加0应该等于自身', function() {
expect(add(1, 0)).to.be.equal(1);
上面代码的这个测试用例不会执行。
十二、浏览器测试
除了在命令行运行,Mocha还可以在浏览器运行。
首先,使用mocha init命令在指定目录生成初始化文件。
$ mocha init demo08
运行上面命令,就会在目录下生成文件,以及配套的脚本和样式表。
&!DOCTYPE html&
&h1&Unit.js tests in the browser with Mocha&/h1&
&div id="mocha"&&/div&
&script src="mocha.js"&&/script&
mocha.setup('bdd');
&script src="tests.js"&&/script&
mocha.run();
然后,新建一个源码文件。
function add(x, y) {
return x +
然后,把这个文件,以及断言库chai.js,加入index.html。
mocha.setup('bdd');
&script src="add.js"&&/script&
&script src="/chai.js"&&/script&
&script src="tests.js"&&/script&
mocha.run();
最后,在里面写入测试脚本。
var expect = chai.
describe('加法函数的测试', function() {
it('1 加 1 应该等于 2', function() {
expect(add(1, 1)).to.be.equal(2);
it('任何数加0等于自身', function() {
expect(add(1, 0)).to.be.equal(1);
expect(add(0, 0)).to.be.equal(0);
现在,在浏览器里面打开index.html,就可以看到测试脚本的运行结果。
十三、生成规格文件
Mocha支持从测试用例生成规格文件。
进入子目录,运行下面的命令。
$ mocha --recursive -R markdown > spec.md
上面命令根据test目录的所有测试脚本,生成一个规格文件。-R markdown参数指定规格报告是markdown格式。
如果想生成HTML格式的报告,使用下面的命令。
$ mocha --recursive -R doc > spec.html
前面的文章介绍了 Systemd 的操作命令和基本用法,今天给出一个实例,如何使用 Systemd 启动一个 Node 应用。
越来越多的人,使用React开发Web应用。它的测试就成了一个大问题。
(说明:本文选自我的新书《ES6 标准入门(第二版)》的第一章《ECMAScript 6简介》)
npm 是 Node 的模块管理器,功能极其强大。它是 Node 获得成功的重要原因之一。

我要回帖

更多关于 mocha 测试 的文章

 

随机推荐