本次翻译时间为2016年9月底,目前Mocha的版本为3.1.0。
官方文档地址: http://mochajs.org/
—— Awey
1. 简介
Mocha是一个能够运行在Node和浏览器中的多功能的JavaScript测试框架,它让异步测试简单且有趣。Mocha连续地运行测试,并给出灵活而精确的报告,同时能够将错误精确地映射到测试用例上。它托管在GitHub上。
2. 支持者
觉得Mocha很有帮助?成为支持者并以每月捐赠的形式支持Mocha。
3. 赞助商
公司正在使用Mocha?询问你的上司或者市场部看看他们是否捐赠过Mocha。(如果捐赠过)你们公司的LOGO会展示在npmjs.com和我们的github仓库
4. 特性
- 支持浏览器
- 支持简单异步,包括promise
- 测试覆盖率报告
- 支持字符串比较
- 提供JavaScript API来运行测试
- 为持续集成等需求提供适当的退出状态
- non-ttys 自动检测和禁用颜色
- 异步测试超时
- ... ...(后略)
5. 目录
略。
本次翻译并未完全按照官方文档的文档结构进行。
6. 开始使用
6.1 安装
npm 全局安装:
npm install --global mocha
或者作为开发依赖安装在项目中:
npm install mocha --save-dev
安装Mocha v3.0.0或者更新的版本,你需要v1.4.0或者更新版本的npm。此外,运行Mocha的Node版本不能低于v0.10
Mocha也能通过Bower安装,还可通过cdnjs进行引用。
6.2 起步
npm install mocha
mkdir test
$EDITOR test/test.js # 或者使用你喜欢的编辑器打开
在编辑器中:
var assert = require('assert')
describe('Array', function () {
describe('#indexOf()', function() {
it('未找到值时应当返回-1', function () {
assert.equal(-1, [1, 2, 3].indexOf(4))
})
})
})
回到命令行:
Array
#indexOf()
√ 未找到值时应当返回-1
1 passing (9ms)
6.3 断言
Mocha允许你使用你喜欢的断言库。在之后的例子中,我们使用了Node中内置的断言模块——但通常情况下,只要它能抛出异常就行[1]。这意味着你可以使用下列断言库:
- should.js - BDD风格贯穿始终
- expect.js - expect() 风格的断言
- chai - expect()、assert()和 should风格的断言‘
- better-assert - C风格的自文档化的assert()
- unexpected - “可扩展的BDD断言工具”
6.4 异步代码
用Mocha测试异步代码简单的不要不要的!测试运行完了调用一下回调函数就行。只需要在it()
中添加一个回调[2],Mocha就知道应该等到这个回调被调用时才结束这个测试用例的运行。
describe('User', function () {
describe(#'save()', function () {
it('应当正常保存', function () {
var user = new User('Luna')
user.save(function (err) {
if (err) done(err)
else done()
})
})
})
})
简便起见,done()
函数接受一个error参数,所以上面的代码可以这么写:
describe('User', function () {
describe(#'save()', function () {
it('应当正常保存', function () {
var user = new User('Luna')
user.save(done)
})
})
Promise
有时,与其使用done()
回调函数,你会想在你的异步代码中返回一个Promise[3],当你正在测试的API是返回一个Promise而不是使用回调时这会很有帮助:
beforeEach(function () {
return db.clear()
.then(function () {
return db.save([tobi, loki, jane])
})
})
describe('#find()', function () {
it('返回匹配的记录', function () {
return db.find({ type: 'User' }).should.eventually.have.length(3)
})
})
接下来的例子将会使用chai-as-promised来获得流畅的promise断言
在Mocha 3.0及更新的版本中,同时返回一个Promise和调用done()
会导致一个异常,下面的代码是错误的:
const assert = require('assert')
it('应该结束这个测试用例', function (done) {
return new Promise(function (resolve) {
assert.ok(true)
resolve()
})
.then(done)
})
上面的测试会报错:Error: Resolution method is overspecified. Specify a callback *or* return a Promise; not both.
。在v3.0.0以下的版本,done()
会被忽略(而不会报错)。
6.5 同步代码
当测试同步代码的时候,省略回调函数[4],Mocha就会自动执行下一条测试。
describe('Array', function () {
describe('#indexOf()', function () {
it('没有找到时应当返回-1', function () {
[1, 2, 3].indexOf(5).should.equal(-1)
[1, 2, 3].indexOf(0).should.equal(-1)
})
})
})
6.6 箭头函数
不建议在Mocha中使用箭头函数(“lambdas”)。由于(箭头函数特殊的)this
绑定语法,箭头函数无法访问Mocha的上下文。例如,下面的代码会因为使用了箭头函数而执行失败:
describe('my suit', () => {
it('my test', () => {
// 应当设置1000毫秒延迟,而不是执行失败
this.timeout(1000)
assert.ok(true)
})
})
<small>当然如果你不需要使用Mocha的上下文,使用lambdas就没有问题了。然而这样的做的结果是你的测试代码将难以重构</small>
6.7 钩子函数
Mocha默认使用“BDD”风格的接口,提供了before()
,after()
,beforeEach()
和afterEach()
四个钩子函数。这些函数可以用来(在测试前)做预处理工作或在测试后清理工作。
describe('hooks', function () {
before(function () {
// 在这个作用域的所有测试用例运行之前运行
})
after(function () {
// 在这个作用域的所有测试用例运行完之后运行
})
beforeEach(function () {
// 在这个作用域的每一个测试用例运行之前运行
})
afterEach(function () {
// 在这个作用域的每一个测试用例运行之后运行
})
// 测试用例
})
测试用例和测试的钩子可以混合排列。(相同的)钩子函数会按照它们的书写顺序运行;(整体的运行顺序是)所有的
before()
钩子运行一次,然后是beforeEach()
钩子,测试用例,afterEach()
钩子(循环运行),最后是after()
钩子(运行一次)
钩子函数的描述参数
所有的钩子在调用时都可以提供一个可选的“描述信息”的参数,以便在你的测试中更精确地定位错误。如果给一个钩子函数传入一个命名函数,当未提供“描述信息”参数的时候,这个命名函数的名称将被作为描述信息。
beforeEach(function () {
// beforeEach hook
})
beforeEach(function namedFun () {
// beforeEach: namedFun
})
beforeEach('一些描述信息' ,function () {
// beforEach: 一些描述信息
})
异步钩子
所有钩子(before()
, after()
, beforeEach()
, afterEach()
)既可以是同步的也可以是异步的,(这一点上)它们的行为与普通的测试用例非常相似[5]:
describe('连接', function () {
var db = new Connection,
tobi = new User('tobi'),
loki = new User('loki'),
jane = newUser('jane')
beforeEach(function (done) {
db.clear(function (err) {
if (err) return done(err)
db.save([tobi, loki, jane], done)
})
})
describe('#find()', function () {
it('返回匹配的记录', function (done) {
db.find({type: 'User'}, function (err, res) {
if (err) return done(err)
res.should.have.length(3)
})
})
})
})
全局钩子
你可以在任意(测试)文件中添加“全局”级别的钩子函数,例如,在所有describe()
作用域之外添加一个beforeEach()
,它的回调函数会在所有的测试用例运行之前运行,无论(这个测试用例)处在哪个文件(这是因为Mocha有一个隐藏的describe()
作用域,称为“根测试套件 root suite”)。
beforeEach(function () {
console.log('在所有文件的所有测试用例之前运行')
})
延迟的根测试套件
如果你需要在所有测试套件运行之前进行一些异步操作,你可以延迟根测试套件。以--delay
参数运行mocha
[6],这会在全局注入一个特殊的回调函数run()
:
setTimeout(function () {
// 一些设置
describe('我的测试套件', function () {
// ...
})
run()
}, 5000)
6.8 挂起测试(Pending Tests)
“Pending”——“有人最终会编写这些测试用例”——没有传入回调函数的测试用例[7]:
describe('Array', function () {
describe('#indexOf()', function () {
// 挂起的测试用例
it('未找到时应当返回-1')
})
})
挂起的测试用例会在报告中出现“pending”状态。
6.9 独占测试
通过向测试套件或测试用例函数添加.only
后缀,独占特性允许你只运行指定的测试套件或测试用例。下面是一个独占测试套件的例子:
describe('Array', function (){
describe.only('#indexOf()', function () {
// ...
})
})
<small>注意:所有嵌套(在.only
套件中的)测试套件仍旧会运行</small>
下面是一个运行单个测试用例的例子:
describe('Array', function (){
describe('#indexOf()', function () {
it.only('除非找到否则返回-1', function () {
// ...
})
it('找到后应当返回下标', function () {
// ...
})
})
})
在v3.0.0版本以前,only()
使用字符串匹配来决定哪些测试需要执行。v3.0.0以后的版本only()
可以使用多次来定义测试用例的子集去运行:
describe('Array', function() {
describe('#indexOf()', function() {
it.only('should return -1 unless present', function() {
// 这个测试用例会运行
})
it.only('should return the index when present', function() {
// 这个测试用例也会运行
})
it('should return -1 if called with a non-Array context', function() {
// 这个测试用例不会运行
})
})
})
你也可以选择多个测试套件:
describe('Array', function() {
describe.only('#indexOf()', function() {
it('should return -1 unless present', function() {
// 这个测试用例会运行
})
it('should return the index when present', function() {
// 这个测试用例也会运行
})
})
describe.only('#concat()', function () {
it('should return a new Array', function () {
// 这个测试用例也会运行
})
})
describe('#slice()', function () {
it('should return a new Array', function () {
// 这个测试用例不会运行
})
})
})
但测试会存在优先级[8]:
describe('Array', function() {
describe.only('#indexOf()', function() {
it.only('should return -1 unless present', function() {
// 这个测试用例会运行
})
it('should return the index when present', function() {
// 这个测试用例不会运行
})
})
})
<small>注意,如果提供了钩子函数,钩子函数仍会执行</small>
<small>注意不要把
.only
提交到版本控制上,除非你明确知道你在做什么</small>
6.10 跳过测试
这个功能是only()
的反面。通过后缀skip()
就可以让Mocha忽略这个测试套件或测试用例。所有被跳过的测试都会被标记为pending
状态并体现在报告中。下面是一个跳过一整个测试套件的例子:
describe('Array', function() {
describe.skip('#indexOf()', function() {
// ...
})
})
下面是一个跳过测试用例的例子:
describe('Array', function() {
describe('#indexOf()', function() {
it.skip('should return -1 unless present', function() {
// 这个测试用例不会运行
})
it('should return the index when present', function() {
// 这个测试用例会运行
})
})
})
最佳实践:使用
skip()
而不是直接将测试注释掉
你也可以使用this.skip()
在运行时跳过测试。如果测试需要的环境或配置没办法提前检测,可以考虑使用运行时跳过。例如:
it('应该仅在正确的环境配置中测试', function () {
if(/*测试环境正确*/) {
// 编写断言
} else {
this.skip()
}
})
因为这个测试什么也没做[9],它会被报告为passing
。
最佳实践:不要什么也不做[10]!一个测试应当编写断言或者使用
this.skip()
如果想以这种方式跳过多个测试[11],可以在一个befor()
钩子函数中调用this.skip()
:
before(function() {
if (/* check test environment */) {
// setup code
} else {
this.skip()
}
})
在Mocha v3.0.0版本以前,钩子函数和异步测试中不支持
this.skip()
6.11 重试测试
你可以选择将失败的测试重试一定的次数。这个特性被设计用于资源(数据)不容易被仿造的端到端(end-to-end)测试(functional tests/Selenium…)。不推荐将这个特性用于单元测试。
这个特性会重新运行beforeEach()
/afterEach()
钩子,但不会运行before()
/after()
钩子。
注意:下面的例子使用了Selenium webdriver(为Promise链式调用改写了Mocha的全局钩子)。
describe('retries', function() {
// 测试套件中的所有测试用例将被重试4次
this.retries(4)
beforeEach(function () {
browser.get('http://www.yahoo.com');
})
it('should succeed on the 3rd try', function () {
// 指定这个测试用例仅重试2次
this.retries(2)
expect($('.foo').isDisplayed()).to.eventually.be.true
})
})
6.12 动态生成测试
可以使用Function.prototype.call
和函数表达式来定义测试套件和测试用例,以动态生成测试而不需要其它的特殊语法——简单的JavaScript就能用于实现你可能在其它测试框架中见到过的类似“参数化”测试的功能。
例如:
var assert = require('chai').assert
function add() {
return Array.prototype.slice.call(arguments).reduce(function(prev, curr) {
return prev + curr
}, 0)
}
describe('add()', function() {
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.length + ' args', function() {
var res = add.apply(null, test.args)
assert.equal(res, test.expected)
})
})
})
上面的代码将会生成一个带有三个测试用例的测试套件:
$ mocha
add()
✓ correctly adds 2 args
✓ correctly adds 3 args
✓ correctly adds 4 args
6.13 测试耗时
许多测试报告都会显示测试耗时,并且标记出那些耗时较长的测试,就像下面的报告显示的那样:
你可以使用slow()
方法来定义到底多久才算“耗时较长”:
describe('something slow', function() {
this.slow(10000)
it('它的耗时应该足够我去做个三明治了', function() {
// ...
})
})
6.14 测试超时
套件级别
套件级别的超时应用于整个测试套件,你也可以通过this.timeout(0)
来取消超时限制。如果没有覆盖这个值的话[12],所有嵌套的测试套件和测试用例都会继承这个超时限制。
describe('a suite of tests', function() {
this.timeout(500)
it('应当不超过500毫秒', function(done){
setTimeout(done, 300)
})
it('也应当不超过500毫秒', function(done){
setTimeout(done, 250)
})
})
用例级别
也可以对单一用例设置超时时间,或者通过this.timeout(0)
来取消超时限制:
it('应该不超过500毫秒', function(done){
this.timeout(500)
setTimeout(done, 300)
})
钩子级别
当然也可以设置钩子级别的超时:
describe('一个测试套件', function() {
beforeEach(function(done) {
this.timeout(3000); // 一个用时很长的环境设置操作.
setTimeout(done, 2500)
})
})
同样,使用this.timeout(0)
来取消超时限制
在v3.0.0或更新的版本中,给
this.timeout()
传递一个大于最大延迟值的参数会让超时限制失效
6.15 差异比较
Mocha支持断言库抛出的AssertionErrors
的两个属性err.expected
和err.actual
。Mocha会尝试显示期望(的代码)和断言库真正看到的的代码之间的差异。这里有一个“string”差异的例子:
7. 命令行
Usage: mocha [debug] [options] [files]
Commands:
init <path> initialize a client-side mocha setup at <path>
Options:
-h, --help 显示使用帮助
-V, --version 显示版本信息
-A, --async-only 强制所有测试带有回调(异步)或返回一个promise
-c, --colors 强制启用颜色
-C, --no-colors 强制关闭颜色
-G, --growl 启用弹出消息
-O, --reporter-options <k=v,k2=v2,...> 测试报告工具详细设置
-R, --reporter <name> 指定测试报告工具
-S, --sort 测试文件排序
-b, --bail 第一次测试不通过立即结束测试
-d, --debug 开启node的debugger模式, 同node --debug
-g, --grep <pattern> 只运行匹配<pattern>的测试
-f, --fgrep <string> 只运行包含<string>的测试
-gc, --expose-gc 暴露gc扩展
-i, --invert 反转--grep 和--fgrep 匹配
-r, --require <name> 加载指定模块
-s, --slow <ms> 以毫秒为单位定义"慢" 测试门槛 [75]
-t, --timeout <ms> 以毫秒为单位设置测试用例超时时间 [2000]
-u, --ui <name> 指定用户接口 (bdd|tdd|qunit|exports)
-w, --watch 监测文件变动
--check-leaks 检查全局变量泄露
--full-trace 显示完整的跟踪堆栈
--compilers <ext>:<module>,... 使用指定的模块编译文件
--debug-brk 在首行启用node的debugger断点
--globals <names> allow the given comma-delimited global [names](没办法强行翻译了)
--es_staging 开启所有过时的特性
--harmony<_classes,_generators,...> all node --harmony* flags are available
--preserve-symlinks 命令模块加载器在解析和缓存模块时保留符号链接
--icu-data-dir 包括ICU数据
--inline-diffs 在行内显示实际/预期的字符差异
--interfaces 显示可用的接口(bdd|tdd|qunit|exports)
--no-deprecation 禁用警告
--no-exit 请求一个彻底的事件循环终止: Mocha不会调用 process.exit
--no-timeouts 禁用超时, 隐含 --debug
--opts <path> 指定选项路径
--perf-basic-prof enable perf linux profiler (basic support)
--prof 记录统计分析信息
--log-timer-events 记录包含外部回调的时间点
--recursive 包含子目录
--reporters 显示可用的测试报告工具
--retries <times> 设置重试未通过的测试用例的次数
--throw-deprecation 当使用了废弃的方法时抛出异常
--trace 追踪函数借调
--trace-deprecation 显示废弃的跟踪堆栈
--use_strict 强制严格模式
--watch-extensions <ext>,... --watch 上附加的监控扩展
--delay 等待异步套件定义
-w
,--watch
初始化后,监测文件变动运行测试
--compilers
CoffeeScript不再被直接支持。这类预编译语言可以使用相应的编译器扩展来使用,比如CS1.6:--compilers coffee:coffee-script
和CS1.7+:--compilers coffee:coffee-script/register
babel-register
如果你的ES6模块是以.js
为扩展名的,你可以npm install --save-dev babel-register
,然后--require babel-register; --compilers
就可以指定文件扩展名
-b
,--ball
只对首个异常感兴趣?使用--bail
-d
,--debug
开启node的调试模式,这会用node debug <file ...>
来执行你的脚本,允许你逐行调试代码并用debugger
声明来打断点。注意mocha debug
和mocha --debug
的区别:mocha debug
会启动node内置的debug客户端,mocha --debug
则允许你使用其它调试工具——比如Blink Developer Tools。
--globals <name>
接受一个以逗号分隔的全局变量名,例如,如果你的应用有意暴露一个全局变量名app
或YUI
,你可能就会使用--globals app,YUI
。它还接受通配符。--globals '*bar'
会匹配foobar, barbar
等。你也可以简单地传入*
来忽略所有全局变量。
check-leaks
在运行测试时,Mocha默认不会检查全局变量泄露,可以使用--check-leaks
来开启这一功能,使用--globals
来指定接受的全局变量比如--globals jQuery,MyLib
。
-r
,--require
<module-name>
--require
选项对诸如should.js一类的库很有用,所以你可以使用--require should
而不是在每一个测试文件中都调用require('should')
。需要注意的是因为should
是增强了Object.prototype
所以可以正常使用,然而假如你希望访问某模块的输出你就只能require
它们了,比如var should = require('should')
。此外,还可以使用相对路径,比如--reqiure ./test/helper.js
-u
,--ui
<name>
--ui
选项让你指定想使用的接口,默认为“bdd”。
-R
,--reporter
<name>
--reporter
选项允许你指定希望使用的报告器,默认为“spec”。这个标记也可以用来使用第三方的报告器。例如,如果你npm install mocha-locv-reporter
,你可以--reporter mocha-locv-reporter
。
-t
,--timeout
<ms>
指定测试用例超时时间,默认为2秒。你可以传入毫秒数或者一个带s
单位后缀的秒数进行覆盖,例如--timeout 2s
和--timeout 2000
是等价的。
s
,--slow
<ms>
指定“慢”测试阈值,默认为75毫秒。Mocha用这个去高亮那些耗时过长的测试。
-g
,--grep
<pattern>
指定--grep
选项让Mocha只运行匹配<pattern>
的测试,<pattern>
将会作为正则表达式进行解析。
假如,像下面的片段那样,你有一些“api”相关的测试和一些“app”相关的测试;则前者可以使用--grep api
来运行,后者可使用--grep --app
来运行
describe('api', function() {
describe('GET /api/users', function() {
it('respond with an array of users', function() {
// ...
})
})
})
describe('app', function() {
describe('GET /users', function() {
it('respond with an array of users', function() {
// ...
})
})
})
8.接口[13]
Mocha的“接口”系统允许开发者选择习惯的风格或DSL。Mocha有BDD,TDD,Exports,QUnit和Require风格的接口。
8.1 BDD
BDD接口提供describe()
,context()
,it()
,specify()
,before()
,after()
,beforeEach()
和afterEach()
。
context()
只是describe()
的别名,二者表现也是一致的;它只是为了让测试可读性更高。同样specify()
也是it()
的别名。
前文所有的示例都是使用BDD接口编写的
describe('Array', function() {
before(function() {
// ...
})
describe('#indexOf()', function() {
context('when not present', function() {
it('should not throw an error', function() {
(function() {
[1,2,3].indexOf(4)
}).should.not.throw()
})
it('should return -1', function() {
[1,2,3].indexOf(4).should.equal(-1);
})
})
context('when present', function() {
it('should return the index where the element first appears in the array', function() {
[1,2,3].indexOf(3).should.equal(2)
})
})
})
})
8.2 TDD
TDD接口提供suite()
,test()
,suiteSetup()
,suiteTeardown()
,setup
和teardown()
:
suite('Array', function() {
setup(function() {
// ...
})
suite('#indexOf()', function() {
test('should return -1 when not present', function() {
assert.equal(-1, [1,2,3].indexOf(4));
})
})
})
8.3 EXPORTS
EXPORTS接口很像Mocha的前身expresso,键值before
,after
,beforeEach
,afterEach
是特殊用例,对象类型的属性值是测试套件,方法类型的属性值是测试用例:
module.exports = {
before: function() {
// ...
},
'Array': {
'#indexOf()': {
'should return -1 when not present': function() {
[1,2,3].indexOf(4).should.equal(-1)
}
}
}
}
8.4 QUNIT
类QUnit接口与QUnit的“扁平化”外观相匹配[14],测试套件只需要简单地在测试用例之前定义就行。和TDD类似,它使用suite()
和test()
,但又类似于BDD,也包含了before()
,after()
,beforeEach()
和afterEach()
。
function ok(expr, msg) {
if (!expr) throw new Error(msg)
}
suite('Array')
test('#length', function() {
var arr = [1,2,3]
ok(arr.length == 3)
})
test('#indexOf()', function() {
var arr = [1,2,3]
ok(arr.indexOf(1) == 0)
ok(arr.indexOf(2) == 1)
ok(arr.indexOf(3) == 2)
})
suite('String')
test('#length', function() {
ok('foo'.length == 3)
})
8.5 REQUIRE
require
风格接口允许你直接用require
语句引入describe
等函数并在任意位置使用它们。当你希望在你的测试中禁用全局变量时这也会很有用。
<small>注意,require
风格接口不能通过node直接运行,必须通过Mocha运行</small>
var testCase = require('mocha').describe
var pre = require('mocha').before
var assertions = require('mocha').it
var assert = require('chai').assert
testCase('Array', function() {
pre(function() {
// ...
});
testCase('#indexOf()', function() {
assertions('should return -1 when not present', function() {
assert.equal([1,2,3].indexOf(4), -1)
})
})
})
9. 测试报告
Mocha的测试报告与命令行窗口适配,且当标准输出串口没有关联到打印机时始终禁用ANSI-escape颜色。
9.1 SPEC
这是默认的测试报告。“SPEC”测试报告输出与测试用例一致的嵌套视图。
9.2 Dot Matrix
Dot Matrix(或者Dot)测试报告使用一串简单字符来表示测试用例,失败的(failing)以红色叹号(!)表示,挂起的(pedding)以蓝色逗号(,)表示,长时的以黄色表示。当你希望最小化输出的时候这就很好。
9.3 NYAN
NYAN测试报告就是你想的那样(一只猫):
9.4 TAP
TAP测试报告的输出很适合Test-Anything-Protocol的用户。
9.5 Landing Strip
landing Strip(landing)测试报告是一个非正式的测试报告器,它用unicode字符模仿了飞机降落的情景。
9.6 LIST
list测试报告输出一个测试用例通过或失败的简洁列表,并在底部输出失败用例的详情。
9.7 PROGRESS
progress测试报告展示一个简单进度条。
9.8 JSON
JSON测试报告在测试完成后输出一个大JSON对象。
9.9 JSON STREAM
JSON stream测试报告输出根据“事件”断行了的JSON,以“start”事件开始,紧跟着测试通过或失败,最后是“end”事件。
9.10 MIN
min测试报告仅显示结果摘要,当然也输出失败时的错误信息。当与--watch
一起使用时很棒,它会清空你的命令行让测试摘要始终显示在最上方。
9.11 DOC
doc测试报告输出一个层级化的HTML来表示你的测试结果。使用header,footer和一些样式来包裹测试结果,然后你就有了一份惊艳的测试报告文档!
例如,假定你有下面的JavaScript:
describe('Array', function() {
describe('#indexOf()', function() {
it('should return -1 when the value is not present', function() {
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
});
});
});
在命令行输入mocha --reporter doc array
会输出:
<section class="suite">
<h1>Array</h1>
<dl>
<section class="suite">
<h1>#indexOf()</h1>
<dl>
<dt>should return -1 when the value is not present</dt>
<dd><pre><code>[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);</code></pre></dd>
</dl>
</section>
</dl>
</section>
The SuperAgent request library test documentation was generated with Mocha’s doc reporter using this simple make target:
test-docs:
$(MAKE) test REPORTER=doc \
| cat docs/head.html - docs/tail.html \
> docs/test.html
View the entire Makefile for reference.
9.12 MARKDOWN
markdown测试报告为你的测试讨价能生成一个markdown TOC。当你希望将你的测试结果放在Github的wiki或仓库中时,这会很好用。这是一个例子的链接测试输出
9.13 HTML
HTML测试报告是当前Mocha唯一支持的浏览器测试报告,长得像这样:
9.14 未记载的测试报告
XUnit测试报告也是可以用的。默认地,它输出到console。想直接写入文件,使用--reporter-options output=filename.xml
。
9.15 第三方的测试报告
Mocha允许自定义第三方的测试报告生成器。浏览wiki获取更多信息。一个例子是TeamCity reporter。
10. 在浏览器中运行Mocha
Mocha可以运行在浏览器中。Mocha的每个释出版本都会有./mocha.js
和./mocha.css
来在浏览器中使用。
10.1 浏览器专用方法
下面的方法仅在浏览器环境中有效:
mocha.allowUncaught()
:如果调用,未捕获的错误不会被error handler处理。
一个典型的设置看起来可能像下面这样,在载入测试脚本,在onload
中用mocha.run()
运行它们之前,我们调用mocha.setup('bdd')
来使用BDD风格的接口。
<html>
<head>
<meta charset="utf-8">
<title>Mocha Tests</title>
<link href="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.css" rel="stylesheet" />
</head>
<body>
<div id="mocha"></div>
<script src="https://cdn.rawgit.com/jquery/jquery/2.1.4/dist/jquery.min.js"></script>
<script src="https://cdn.rawgit.com/Automattic/expect.js/0.3.1/index.js"></script>
<script src="https://cdn.rawgit.com/mochajs/mocha/2.2.5/mocha.js"></script>
<script>mocha.setup('bdd')</script>
<script src="test.array.js"></script>
<script src="test.object.js"></script>
<script src="test.xhr.js"></script>
<script>
mocha.checkLeaks();
mocha.globals(['jQuery']);
mocha.run();
</script>
</body>
</html>
10.2 grep
浏览器中也可以使用--grep
功能。在你的URL上添加一个请求参数:?grep=api
。
10.3 浏览器配置
Mocha的选项可以通过mocha.setup()
来配置。比如:
// Use "tdd" interface. This is a shortcut to setting the interface;
// any other options must be passed via an object.
mocha.setup('tdd');
// This is equivalent to the above.
mocha.setup({
ui: 'tdd'
});
// Use "tdd" interface, ignore leaks, and force all tests to be asynchronous
mocha.setup({
ui: 'tdd',
ignoreLeaks: true,
asyncOnly: true
});
10.4 浏览器专用选项
下面的选项仅在浏览器环境有效:
noHighlighting
:如果设置为true
,do not attempt to use syntax highlighting on output test code。
mocha.opts
回到服务器,Mocha会试图加载./test/mocha.opts
作为Mocha的配置文件。文件是由命令行参数按行拼接起来的。命令行参数也是有优先级的,例如,假定你有下面的mocha.opt
文件:
--require should
--reporter dot
--ui bdd
它会将默认测试报告设置为dot,加载should
断言库,并使用BDD风格的接口。然后你可能会继续带参数运行Mocha,这里是开启Growl支持,并将测试报告更换为list:
$ mocha --reporter list --growl
11. test/
文件夹
Mocha默认会全局寻找./test/*.js
和./test/*.coffee
,所以你可能需要将你的测试文件放到./test
文件夹中
12. 编辑器插件
下面的编辑器插件package可用:
12.1 TextMate
Mocha的TextMate包包含了能够加速测试编写的代码片段。克隆Mocha repo并运行make tm
来安装这个包
12.2 JetBrains
JetBrains为它们的IDE套件(IntelliJ IDEA,WebStorm等)提供了一个NodeJS插件,包含了一个Mocha test runner,和一些周边。
插件名为NodeJS,并且可以通过Preference > Plugins来安装...如果你的许可允许的话。
12.3 Wallaby.js
Wallaby.js是一个持续测试工具,为JetBrains IDE和Visual Studio中的Mocha提供实时的测试覆盖率,不管是运行在node.js还是浏览器的项目。
12.4 Emacs
Emacs支持通过第三方插件mocha.el来运行Mocha测试。插件可以在MELPA上找到,也可通过M-x package-install mocha
来安装。
13. 案例
真实案例代码:
14. 测试Mocha
运行Mocha本身的测试,你可能需要GUN Make或者其它兼容的环境;Cygwin应该就可以。
$ cd /path/to/mocha
$ npm install
$ npm test
使用不同的测试报告:
$ REPORTER=nyan npm test
15. 更多信息
除了在Gitter上与我们交谈,也可以去GitHub上的Mocha Wiki获取诸如 using spies、mocking和shared behaviours等更多信息。加入Google Group进行讨论。查看example/tests.html获取Mocha运行实例。查看source获取 JavaScript API。
-
译者注:这里的意思是,只要这个断言库在遇到测试不通过时会抛出异常(throws an Error),它就可以使用在Mocha中。这意味着即使你不使用任何断言库,完全自己实现测试代码,只要在遇到测试部不通过时你抛出异常,也是可以的,不过通常没有人愿意这么费力不讨好 ↩
-
译者注:在it()函数的第二个参数,也就是it的回调函数中,添加一个参数,这个参数也是一个回调函数,命名随意,通常都会命名为
done
,然后在异步代码运行完毕后调用它即可 ↩ -
译者注:这是为了避开无穷的回调漩涡 ↩
-
译者注:这里指的是省略done()这个回调函数 ↩
-
译者注:还记得前文提到的done()回调函数么,在这些钩子中处理异步代码与在测试用例中处理异步代码是一样的 ↩
-
译者注:这是指在命令行运行 mocha 命令时带上 --delay参数,下文的setTimeout仅做演示用,并非真实的异步操作 ↩
-
译者注:这里的意思是,可以使用挂起的测试用例来占个位置,先写上测试用例,但可能由于某些原因,比如被测代码还未实现,这个测试用例的内容将在稍后编写,这样的测试用例既不会pass也不会fail,而是处于pendding状态 ↩
-
译者注:这里指的是嵌套的only()会存在优先级 ↩
-
译者注:这里所谓的“什么也没做”指的是当测试环境不正确时,测试代码什么也没做,只是简单的跳过了 ↩
-
译者注:这里的“什么也不做”与前文的“什么也不做”不是一个意思,这里的意思是既不写断言也不跳过,只是简单地空在那里(简单地空在那里这个测试的状态也会是passing) ↩
-
译者注:这种方式指的是,判断测试环境是否准本好并使用this.skip()来跳过测试 ↩
-
译者注:“覆盖这个值”指的是在嵌套的测试套件或者测试用例中再次通过this.timeout()来进行超时限制从而覆盖父级套件的设置 ↩
-
译者注:指的是接口风格 ↩
-
译者注:这里指的是编程风格扁平化,即没有多层嵌套 ↩