初识 mocha in Nodejs

初识 mocha in Nodejs

囧,cnodejs不能上传图。有图版请见 无图无真相!

NodeJS里最常用的测试框架估计就是mocha了。它支持多种node的assert libs, 同时支持异步和同步的测试,同时支持多种方式导出结果,也支持直接在browser上跑Javascript代码测试。

本文示例大多源于官网示例,部分示例结合需要或自己的感想有所改动。更多介绍请看 官方网址:Mocha on Github

Installation:

当你成功安装nodejs v0.10 和 npm后执行下面这条命令。

# npm install -g mocha

p.s. Ubuntu的注意apt源里的nodejs版本会比较旧,某些module会不支持,请从nodejs官网进行源码安装。

First step to Mocha:

以下为最简单的一个mocha示例:

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));
		})
	})
});
  • describe (moduleName, testDetails) 由上述代码可看出,describe是可以嵌套的,比如上述代码嵌套的两个describe就可以理解成测试人员希望测试Array模块下的#indexOf() 子模块。module_name 是可以随便取的,关键是要让人读明白就好。
  • it (info, function) 具体的测试语句会放在it的回调函数里,一般来说info字符串会写期望的正确输出的简要一句话文字说明。当该it block内的test failed的时候控制台就会把详细信息打印出来。一般是从最外层的describe的module_name开始输出(可以理解成沿着路径或者递归链或者回调链),最后输出info,表示该期望的info内容没有被满足。一个it对应一个实际的test case
  • assert.equal (exp1, exp2) 断言判断exp1结果是否等于exp2, 这里采取的等于判断是== 而并非 === 。即 assert.equal(1, ‘1’) 认为是True。这只是nodejs里的assert.js的一种断言形式,下文会提到同样比较常用的should.js。

如果exp1和exp2均为字符串,字符串比较出错时则控制台会用颜色把相异的部分标出来。

Asynchronous

Frist step 中的代码显然是个 Synchronous 的代码,那么对于异步代码应该怎么做呢?很简单,在你最深处的回调函数中加done()表示结束。

fs = require('fs');
describe('File', function(){
	describe('#readFile()', function(){
    	it('should read test.ls without error', function(done){
	    	fs.readFile('test.ls', function(err){
				if (err) throw err;
				done();
			});
		})
	})
})
  • done ()<br> 按照瀑布流编程习惯,取名done是表示你回调的最深处,也就是结束写嵌套回调函数。但对于回调链来说done实际上意味着告诉mocha从此处开始测试,一层层回调回去。

上例代码是test pass的,我们尝试把test.ls改成不存在的test.as。便会返回具体的错误位置。

这里可能会有个疑问,假如我有两个异步函数(两条分叉的回调链),那我应该在哪里加done()呢?实际上这个时候就不应该在一个it里面存在两个要测试的函数,事实上一个it里面只能调用一次done,当你调用多次done的话mocha会抛出错误。所以应该类似这样:

fs = require('fs');
describe('File', function(){
	describe('#readFile()', function(){
    	it('should read test.ls without error', function(done){
	    	fs.readFile('test.ls', function(err){
				if (err) throw err;
				done();
			});
		})
    	it('should read test.js without error', function(done){
	    	fs.readFile('test.js', function(err){
				if (err) throw err;
				done();
			});
		})
	})
})

Pending

即省去测试细节只保留函数体。一般适用情况比如负责测试框架的写好框架让组员去实现细节,或者测试细节尚未完全正确实现先注释以免影响全局测试情况。这种时候mocha会默认该测试pass。 作用有点像Python的pass。

describe('Array', function(){
	describe('#indexOf()', function(){
  		it('should return -1 when the value is not present', function(){
		})
	})
});

Exclusive && Inclusive

其实很好理解,分别对应only和skip函数。

fs = require('fs');
describe('File', function(){
	describe('#readFile()', function(){
    	it.skip('should read test.ls without error', function(done){
	    	fs.readFile('test.ls', function(err){
				if (err) throw err;
				done();
			});
		})
    	it('should read test.js without error', function(done){
		})
	})
})

上面的代码只会有一个test complete, 只有only的会被执行,另一个会被忽略掉。每个函数里只能有一个only。如果是it.skip ,那么该case就会被忽略。

only和skip共用没有什么实际意义,因为only的作用会把skip屏蔽掉。

fs = require('fs');
describe('File', function(){
	describe('#readFile()', function(){
    	it.skip('should read test.ls without error', function(done){
	    	fs.readFile('test.as', function(err){
				if (err) throw err;
				done();
			});
		})
    	it('should read test.js without error', function(done){
		})
	})
})

上面的代码尽管test.as不存在,但是由于skip,依然会显示test complete。

Before && After

单元测试里经常会用到before和after。mocha同时还提供了beforeEach()和afterEach()。 这里为方便阅读用livescript表示,!->可理解成function(){}。细节无需细读,只需通过框架了解这几个函数如何使用便可。

require! assert
require! fs
can = it

describe ‘Array’, !-> beforeEach !-> console.log ‘beforeEach Array’

before !-&gt;
	console.log 'before Array'

before !-&gt;
	console.log 'before Array second time'

after !-&gt;
	console.log 'after Array'

describe '#indexOf()', !-&gt;
	can 'should return -1 when the value is not present', !-&gt;
		assert.equal -1, [1,2,3].indexOf 0
	can 'should return 1 when the value is not present', !-&gt;

describe 'File', !-&gt;

	beforeEach !-&gt;
		console.log 'beforeEach file test!'

	afterEach !-&gt;
		console.log 'afterEach File test!'

	describe '#readFile()', !-&gt;
		can 'should read test.ls without error', !(done)-&gt;
			fs.readFile 'test.ls', !(err)-&gt;
				if err
					throw err
				done!
		can 'should read test.js without error', !(done)-&gt;
			fs.readFile 'test.js', !(err)-&gt;
				if err
					throw err
				done!

由结果可知(after的使用与before同理),

  • beforeEach会对当前describe下的所有子case生效。
  • before和after的代码没有特殊顺序要求。
  • 同一个describe下可以有多个before,执行顺序与代码顺序相同。
  • 同一个describe下的执行顺序为before, beforeEach, afterEach, after
  • 当一个it有多个before的时候,执行顺序从最外围的describe的before开始,其余同理。

Test Driven Develop (TDD)

mocha默认的模式是Behavior Driven Develop (BDD),要想执行TDD的test的时候需要加上参数,如

mocha -u tdd test.js

前文所讲的describe, it, before, after等都属于BDD的范畴,对于TDD,我们用suite, test, setup, teardown。样例代码如下:

suite 'Array', !->
	setup !->
		console.log 'setup'
teardown !-&gt;
	console.log 'teardown'

suite '#indexOf()', !-&gt;
	test 'should return -1 when not present', !-&gt;
		assert.equal -1, [1,2,3].indexOf 4

<hr>

TDD的一些相关资料:

  1. What is TDD :

http://stackoverflow.com/questions/2327119/what-is-test-driven-development-does-it-require-to-have-initial-designs

  1. Difference between TDD && BDD :

http://stackoverflow.com/questions/4395469/tdd-and-bdd-differences


39 回复

初识 Mocha in Node.js

在Node.js中,Mocha是最常用的测试框架之一。它不仅支持多种Node.js的断言库,还支持异步和同步测试,并且可以以多种方式输出结果,甚至可以直接在浏览器中运行JavaScript代码进行测试。

安装

确保你已经安装了Node.js v0.10及以上版本和npm。然后执行以下命令来全局安装Mocha:

$ npm install -g mocha

如果你使用的是Ubuntu系统,需要注意系统的APT源中的Node.js版本可能较旧,某些模块可能不支持。建议从Node.js官网下载并安装最新版本。

第一步:Mocha 示例

以下是一个简单的Mocha示例:

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));
        });
    });
});
关键概念
  • describe(moduleName, testDetails): describe 用于描述模块和子模块。例如,上述代码中的 describe 表示要测试 Array 模块下的 #indexOf() 子模块。

  • it(info, function): 具体的测试语句会放在 it 的回调函数里。info 字符串通常用来描述期望的正确输出。如果某个 it 块中的测试失败,控制台会打印详细信息。

  • assert.equal(exp1, exp2): 使用 assert.equal 来断言 exp1 是否等于 exp2。这里的判断是基于 == 而不是 ===

异步测试

如果需要测试异步代码,可以在最深层的回调函数中调用 done() 函数来表示测试完成:

fs = require('fs');

describe('File', function(){
    describe('#readFile()', function(){
        it('should read test.ls without error', function(done){
            fs.readFile('test.ls', function(err){
                if (err) throw err;
                done();
            });
        });
    });
});
关键概念
  • done(): 在异步测试中,调用 done() 表示测试完成。如果在 it 块中有多个异步操作,每个操作都需要调用 done()

待办测试

如果暂时不想实现测试细节,可以使用空的 it 块:

describe('Array', function(){
    describe('#indexOf()', function(){
        it('should return -1 when the value is not present', function(){
            // 留待实现
        });
    });
});

排除和包含测试

使用 it.skip 可以排除某个测试,而 it.only 可以指定只运行某个测试:

fs = require('fs');

describe('File', function(){
    describe('#readFile()', function(){
        it.skip('should read test.ls without error', function(done){
            fs.readFile('test.ls', function(err){
                if (err) throw err;
                done();
            });
        });

        it('should read test.js without error', function(done){
            fs.readFile('test.js', function(err){
                if (err) throw err;
                done();
            });
        });
    });
});

前置和后置操作

使用 before, after, beforeEach, afterEach 可以设置一些前置和后置的操作:

require('assert');
require('fs');
const can = it;

describe('Array', function(){
    beforeEach(function(){
        console.log('beforeEach Array');
    });

    before(function(){
        console.log('before Array');
    });

    after(function(){
        console.log('after Array');
    });

    describe('#indexOf()', function(){
        can('should return -1 when the value is not present', function(){
            assert.equal(-1, [1,2,3].indexOf(0));
        });
    });
});

测试驱动开发 (TDD)

Mocha 默认采用行为驱动开发 (BDD) 模式,但也可以切换到测试驱动开发 (TDD) 模式:

$ mocha -u tdd test.js

TDD 模式的代码示例:

suite('Array', function(){
    setup(function(){
        console.log('setup');
    });

    teardown(function(){
        console.log('teardown');
    });

    suite('#indexOf()', function(){
        test('should return -1 when not present', function(){
            assert.equal(-1, [1,2,3].indexOf(4));
        });
    });
});

以上就是Mocha的基本使用方法,希望对你有所帮助!


好文,收藏~

学习下。支持

今天刚好准备学习nodejs测试,果断收藏

顶起, 还了解到livescript.

不错文章,社区支持图片就好了

让你爱上写测试的感觉哈哈

md不能直接上传图片,所以要等社区添加个上传图片的功能啦

md可以贴图… 大家都是搞技术的…找个传图片的地方不难吧… 真找不到就用这个 upload

原来还有这玩意。。是私有接口,还是大家都可以用的。可以宣传一下。。

收藏!

写得很好。

不过Pending tests这个有点问题。不是像你所说的“省去测试细节只保留函数体”,而是不指定回调函数:

describe('Array', function(){
    describe('#indexOf()', function(){
        it('should return -1 when the value is not present');
    });
});

感谢指正。确实是的,应该是without callback。但CnodeJS好像日志时间久了就不给修改了?

求问,为什么我按上面的步骤安装完mocha后,复制第一个实例,运行后报错: describe is not defined??求问

我的node版本是v.10.5

你require了相应的模块吗?第一个demo可是官方demo啊~

问下楼主,it前后可以写before或者after吗?(也就是在describe里边)

好东西

收了

发现单元测试真的很重要,找时间把这块做起来

我觉得这个论坛程序必须要采取些防挖坟措施了,老是看到几年前的帖子被顶上来。。。

收起。

目前支持 ecs6的特性嘛 最近新安装了一个co-mocha说是支持的,但是在实际应用中,却不支持,会报类似这样的错误:

import Fetcher from ‘…/lib/mail_fetcher/126’; ^^^^^^ SyntaxError: Unexpected token import

以前一直都是一知半解,看完此文犹如醍醐灌顶!!!!

mark

我是windows系统 npm install -g mocha 成功了 node app.test 提示 describe is not defined mocha app.test 提示 ‘mocha’ 不是内部或外部命令,也不是可运行的程序或批处理文件。 我的node版本 是 v0.12.7 这个怎么破 求帮忙

棒棒的

初识 mocha in Nodejs

NodeJS里最常用的测试框架之一就是mocha了。它支持多种node的assert库,同时支持异步和同步的测试,并且支持多种方式导出结果,也支持直接在浏览器上运行JavaScript代码测试。

本文示例大多来源于官方示例,部分示例结合需求或个人感想有所改动。更多介绍请查看官方网址:Mocha on Github

Installation

当你成功安装Node.js v0.10和npm后,执行下面这条命令来安装mocha:

# npm install -g mocha

注意: 在Ubuntu系统上,源中的Node.js版本可能较旧,某些模块可能不支持,请从Node.js官网下载并安装最新版本。

First Step to Mocha

以下为最简单的mocha示例:

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

describe (moduleName, testDetails)

describe 可以嵌套,比如上述代码中的 describe 嵌套可以理解为测试人员希望测试 Array 模块下的 #indexOf() 子模块。moduleName 可以随意取名,关键是要让读者能理解其含义。

it (info, function)

具体的测试语句会放在 it 的回调函数里,info 字符串通常用来描述期望的正确输出。当 it block 内的测试失败时,控制台会打印详细的错误信息。一般是从最外层的 describe 开始输出,最后输出 info,表示期望的 info 内容未被满足。

assert.equal (exp1, exp2)

断言判断 exp1 是否等于 exp2。这是 assert.js 的一种断言形式,例如 assert.equal(1, '1') 认为是 True。这与 === 不同。

异步测试

上例中的代码是同步的,那么对于异步代码应该怎么做呢?只需要在最深处的回调函数中添加 done() 即可表示结束。

fs = require('fs');

describe('File', function(){
    describe('#readFile()', function(){
        it('should read test.ls without error', function(done){
            fs.readFile('test.ls', function(err){
                if (err) throw err;
                done();
            });
        });
    });
});

done ()

done() 表示你已完成了所有的工作,回调链已经结束。mocha 会在调用 done() 之后检查测试是否完成。

省略测试细节 (Pending)

省略测试细节仅保留函数体。这通常用于框架开发,让团队成员实现细节,或者测试细节尚未完全实现时防止影响全局测试情况。

describe('Array', function(){
    describe('#indexOf()', function(){
        it('should return -1 when the value is not present', function(){
        });
    });
});

Exclusive & Inclusive

onlyskip 函数分别用于排除和包含测试。

fs = require('fs');

describe('File', function(){
    describe('#readFile()', function(){
        it.skip('should read test.ls without error', function(done){
            fs.readFile('test.ls', function(err){
                if (err) throw err;
                done();
            });
        });

        it('should read test.js without error', function(done){
            fs.readFile('test.js', function(err){
                if (err) throw err;
                done();
            });
        });
    });
});

上面的代码中只有 it 不带 skip 的测试会被执行。

Before & After

在单元测试中常用到 beforeafter。mocha还提供了 beforeEachafterEach

require('assert');
require('fs');

describe('Array', function(){
    beforeEach(function(){
        console.log('beforeEach Array');
    });

    before(function(){
        console.log('before Array');
    });

    after(function(){
        console.log('after Array');
    });

    describe('#indexOf()', function(){
        it('should return -1 when the value is not present', function(){
            assert.equal(-1, [1,2,3].indexOf(0));
        });
    });
});

beforeEach 对当前 describe 下的所有子测试有效。beforeafter 的代码没有特殊的顺序要求。

回到顶部