Mocha
(发音"摩卡")诞生于2011年,是现在最流行的JavaScript测试框架之一,在浏览器和Node环境都可以使用。
它是是做单元测试的,类似的测试框架还有Jasmine
、Karma
、Tape
等
MochaGithub地址
中文文档:https://mochajs.cn/(文档翻译有点问题,建议和原文对照读)
mocha学习:
阮一峰这篇写的很详细,看这篇就好:
http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html
什么是断言?
it('sum(1, 2, 3) should return 6', () => {
assert.strictEqual(sum(1, 2, 3), 6);
})
所谓"断言",就是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误。上面这句断言的意思是,调用sum(1, 2, 3),结果应该等于6。
所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。断言功能由断言库来实现,Mocha本身不带断言库,所以必须先引入断言库。
assert是node内置的断言库
https://nodejs.org/api/assert.html
mocha主要拥有两个API,分别是describe和it。
describe
describe表示一个“测试组件”,描述了一组测试。它是一个函数,第一个参数是测试套件的名称("加法函数的测试"),第二个参数是一个实际执行的函数。
it
it表示一个单元测试(unit test),描述了一个具体的测试,是测试的最小单位。它也是一个函数,第一个参数是测试用例的名称("1 加 1 应该等于 2"),第二个参数是一个实际执行的函数。一个单元测试必须用到断言
开始编写测试
单元测试的文件应当全部放在test文件目录下,mocha默认会执行test目录下的所有测试,因此不要去改变默认目录。
通常,测试脚本与所要测试的源码脚本同名,但是后缀名为.test.js
(表示测试)或者.spec.js
(表示规格)。比如,hello.js
的测试脚本名字就是hello.test.js
假设我们编写了一个hello.js,并且输出一个简单的求和函数:
// hello.js
module.exports = function (...rest) {
var sum = 0;
for (let n of rest) {
sum += n;
}
return sum;
};
假如我们要对hello.js的函数进行测试,那么我们在test文件夹下新建一个hello.test.js,
const assert = require('assert');
const sum = require('../hello');
describe('#hello.js', () => {
describe('#sum()', () => {
it('sum() should return 0', () => {
assert.strictEqual(sum(), 0);
});
it('sum(1) should return 1', () => {
assert.strictEqual(sum(1), 1);
});
it('sum(1, 2) should return 3', () => {
assert.strictEqual(sum(1, 2), 3);
});
it('sum(1, 2, 3) should return 6', () => {
assert.strictEqual(sum(1, 2, 3), 6);
});
});
});
所有的测试用例(it块)都应该含有一句或多句的断言。它是编写测试用例的关键。
执行
mocha add.test.js
mocha
命令后面紧跟测试脚本的路径和文件名,可以指定多个测试脚本。
$ mocha file1 file2 file3
Mocha默认运行test
子目录里面的测试脚本。所以,一般都会把测试脚本放在test
目录里面,然后执行mocha
就不需要参数了。
Mocha默认只执行test
子目录下面第一层的测试用例,不会执行更下层的用例。
为了改变这种行为,就必须加上--recursive
参数,这时test
子目录下面所有的测试用例----不管在哪一层----都会执行。
mocha --recursive
钩
其默认“BDD”式接口,mocha提供钩before()
,after()
,beforeEach()
,和afterEach()
。这些应该用于设置前置条件并在测试后进行清理。
运行顺序:
所有before()
钩子运行(一次)
然后任何beforeEach()
钩子,测试,任何afterEach()
钩子
最后after()
钩子(一次)
多种写法:
beforeEach(function() {
// beforeEach hook
});
beforeEach(function namedFun() {
// beforeEach:namedFun
});
beforeEach('some description', function() {
// beforeEach:some description
});
为啥最终都要return啥呢?
before(() => {
return driver
.initWindow(MOBILE_OTPTIONS);
});
after(() => {
return driver
.openReporter(true)
.quit();
});
箭头功能
不鼓励将箭头函数(“lambdas”)传递给Mocha。Lambdas词法绑定this
,无法访问Mocha上下文。例如,以下代码将失败:
describe('my suite', () => {
it('my test', () => {
// should set the timeout of this test to 1000 ms; instead will fail
this.timeout(1000);
assert.ok(true);
});
});
如果您不需要使用 Mocha的上下文,lambdas应该可以工作。但是,如果最终需要,结果将更难以重构。
根级挂钩
您也可以选择任何文件并添加“root”级别挂钩。例如,beforeEach()
在所有describe()
块之外添加。这将导致回调beforeEach()
在任何测试用例之前运行,无论它存在于哪个文件中(这是因为Mocha有一个隐含的 describe()
块,称为“根套件”)。
beforeEach(function() {
console.log('before every test in every file');
});
测试用例管理
.only()
如果有only,只有only的将被执行
describe.only
it.only
describe('Array', function() {
describe.only('#indexOf()', function() {
it('should return -1 unless present', function() {
// this test will be run
});
it('should return the index when present', function() {
// this test will also be run
});
});
describe.only('#concat()', function () {
it('should return a new Array', function () {
// this test will also be run
});
});
describe('#slice()', function () {
it('should return a new Array', function () {
// this test will not be run
});
});
});
注意:钩子(如果存在)仍将执行。
.skip()
与.only()
相反。通过附加.skip()
,您可以告诉Mocha简单地忽略这些套件和测试用例。跳过的任何内容都将被标记为待处理,并按此报告。
describe.skip
it.skip
describe('Array', function() {
describe('#indexOf()', function() {
it.skip('should return -1 unless present', function() {
// this test will not be run
});
it('should return the index when present', function() {
// this test will be run
});
});
});
您也可以在运行时跳过使用this.skip()
。如果测试需要预先无法检测到的环境或配置,则运行时跳过是合适的。例如:
it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});
上述测试将报告为待定。同样重要的是要注意调用this.skip()
将有效中止测试。
测试持续时间
很多的测试报告都会显示测试所花费的时间,同样也会对一些耗时的测试作出特殊的标记。
Mocha默认会高亮显示超过75毫秒的测试用例
可以用-s
或--slow
调整这个参数。
$ mocha -t 5000 -s 1000 timeout.test.js
上面命令指定高亮显示耗时超过1000毫秒的测试用例。
也可以使用slow()方法来明确的表示出,超过多久的时间,这个测试就可以认为是slow的。
describe('something slow', function() {
this.slow(10000);
it('should take long enough for me to go make a sandwich', function() {
// ...
});
});
异步
Mocha默认每个测试用例最多执行2000毫秒,如果到时没有得到结果,就报错。对于涉及异步操作的测试用例,这个时间往往是不够的,需要用-t
或--timeout
参数指定超时门槛。
it('测试应该5000毫秒后结束', function(done) {
var x = true;
var f = function() {
x = false;
expect(x).to.be.not.ok;
done(); // 通知Mocha测试结束
};
setTimeout(f, 4000);
});
mocha -t 5000 timeout.test.js
上面命令将测试的超时时限指定为5000毫秒。
done
函数。it
块执行的时候,传入一个done
参数,当测试结束的时候,必须显式调用这个函数,告诉Mocha测试结束了。否则,Mocha就无法知道,测试是否结束,会一直等到超时报错。
关于timeout也可不必在命令行中输入,可为单独的用例指定
this.timeout(500);
可在describe 和 it中调用
另外,Mocha内置对Promise的支持,允许直接返回Promise,等到它的状态改变,再执行断言,而不用显式调用done
方法。请看promise.test.js
。
it('异步请求应该返回一个对象', function() {
return fetch('https://api.github.com')
.then(function(res) {
return res.json();
}).then(function(json) {
expect(json).to.be.an('object');
});
});
接口
Mocha的“界面”系统允许开发人员选择他们的DSL风格。Mocha有BDD,TDD,Exports,QUnit和Require -style接口。
TDD(Test-Driven Development)——测试驱动开发
根据客户需求编写测试用例,对功能的过程和接口都进行了设计,而且这种从使用者角度对代码进行的设计通常更符合后期开发的需求。因为关注用户反馈,可以及时响应需求变更,同时因为从使用者角度出发的简单设计,也可以更快地适应变化。
BDD(Behavior-Driven Development)——行为驱动开发
BDD采用更容易测试的软件需求描述方式,来鼓励需求分析人员、软件开发人员、测试人员密切协同开展软件产品研发工作。同时BDD工具可以帮助把用BDD风格描述的业务需求转换成自动化测试脚本,让软件开发人员同步验证自己编写的代码是否满足业务需求描述的产品特性,并在验证软件产品特性的同时形成软件产品特性文档。从而实现了产品研发文档与软件产品代码编写的同步更新。
BDD
的BDD接口提供describe()
,context()
,it()
,specify()
,before()
,after()
,beforeEach()
,和afterEach()
。
context()
只是一个别名describe()
,行为方式相同; 它只是提供了一种让测试更容易阅读和组织的方法。同样,specify()
是别名it()
。
所有前面的示例都是使用BDD接口编写的。
TDD
的TDD接口提供suite()
,test()
,suiteSetup()
,suiteTeardown()
,setup()
,和teardown()
:
mocha项目文件结构
在项目的根目录下,新建一个test文件夹。
└── test
├── config.json
├── helper.js
├── mocha.opts
└── render.test.js
测试文件放在test/
文件夹中
test/mocha.opts文件为mocha命令行参数的默认值
test/
目录
Mocha默认运行test
子目录里面的测试脚本。
mocha.opts
"./test/mocha.opts"文件为mocha命令行参数的默认值
#开头的行都将被视为注释。也可以使用空行。
任何其他行将被视为命令行参数以用作默认设置。每行指定一个设置。
实际命令行中如果有值,将会将对应的默认值覆盖
例如,假设您有以下mocha.opts文件:
# mocha.opts
--require should
--reporter dot
--ui bdd
上面的设置将默认报告者reporter设为dot,需要should库,并用了bdd接口。
将命令行中,输入以下内容,将报告者更改为list,并启用Growl支持:
$ mocha --reporter list --growl
报告器reporter
mocha有各种类型的reporter,默认的是spec
SPEC
Alias: Spec
, spec
mocha的默认报告器
spec报告器输出一个嵌套的分层视图,就像测试用例一样。
第三方reporter
mocha允许自定义报告器,例如
ide插件
vscode的插件:
Mocha sidebar