7

javascript单元测试框架mochajs详解

 1 year ago
source link: https://zoucz.com/blog/2016/08/02/nodejs-unittest-mochajs/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

关于单元测试的想法

对于一些比较重要的项目,每次更新代码之后总是要自己测好久,担心一旦上线出了问题影响的服务太多,此时就希望能有一个比较规范的测试流程。在github上看到牛逼的javascript开源项目,也都是有测试代码的,看来业界大牛们都比较注重单元测试这块。
就我自己的理解而言:我要说话

  • 涉及到大量业务逻辑的代码,可能我没有精力去给每个函数都写上单元测试的代码,功能细节的测试应该交由测试的同事去完成,但是对会直接影响项目正常运行的重要的数据接口,还是可以看情况写上几个单元测试用例的,每一次修改之后跑一跑用例测试一下。
  • 重要的框架底层模块,任何地方出一个小问题,都可能影响到很多服务。对于这种模块,最好是每个函数、每种接口都写上单元测试代码,不然一出问题就是一个大坑啊。
  • 开放出去的公共模块,可以针对主要的函数和接口写上单元测试代码,这样可以确保模块代码比较健壮,看起来也专业一些:)。

基于以上几个想法,我决定学习一款Javascript单元测试框架,并试试去使用它写一些单元测试的代码。
看了很多技术站点和博客的文章,参考了一部分开源项目的测试代码,大致观望下风向,决定学习一下mocha.js这款单元测试框架。
别人的文章都是别人自己学习、咀嚼理解出来的内容,想学的透彻一点,还是自己学习并翻译一遍原版官方的文档比较好。我要说话

mocha单元测试框架简介

mocha是一款功能丰富的javascript单元测试框架,它既可以运行在nodejs环境中,也可以运行在浏览器环境中。
javascript是一门单线程语言,最显著的特点就是有很多异步执行。同步代码的测试比较简单,直接判断函数的返回值是否符合预期就行了,而异步的函数,就需要测试框架支持回调、promise或其他的方式来判断测试结果的正确性了。mocha可以良好的支持javascript异步的单元测试。
mocha会串行地执行我们编写的测试用例,可以在将未捕获异常指向对应用例的同时,保证输出灵活准确的测试结果报告。我要说话

安装mocha

npm install mocha -g 我要说话

一个简单的例子

全局安装mocha后,在项目根目录创建test目录
编写test01.js
我要说话

var assert = require('chai').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));
});
});
});

我要说话

npm install chai --save 安装一下官方文档中使用的chai断言模块(一个用来判断结果是否正确的模块)
打开控制台,在test目录同级运行mocha,得到如下结果:
Array我要说话

  #indexOf()
    √ should return -1 when the value is not present
1 passing (11ms)

可以看到:
describe函数的第一个参数会被输出在控制台中,作为一个用例集的描述,而且这个描述是可以根据自己的需求来嵌套输出的,下面称之为:用例集定义函数
it函数第一个参数用来输出一个用例的描述,前边打个对勾代表测试通过,第二个参数是一个函数,用来编写用例内容,用断言模块来判断结果的正确性,下面称之为用例函数我要说话

mocha支持的断言模块

mocha支持任何可以抛出一个错误的断言模块。例如:should.js、better-assert、expect.js、unexpected、chai等。这些断言库各有各的特点,大家可以了解一下它们的特点,根据使用场景来选择断言库。我要说话

同步代码测试

在测试同步代码的时候,用例函数执行完毕后,mocha就直接开始执行下一个用例函数了。 下面是一个同步测试代码的例子:
我要说话

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来测试异步的代码不要再简单!真的很自信啊~~
只需要在用例函数里边加一个done回调,异步代码执行完毕后调用一下done,就可以通知mocha,我执行完啦,去执行下一个用例函数吧!
就像下面这样:
我要说话

describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) throw err;
done();
});
});
});
});

我要说话

对于上面的情况,判断用例执行成功与否是在异步代码的回调里边完成的,这种情况适用于正确性判断比较复杂的情况。如果异步代码中逻辑错误时,会在回调中抛出一个错误,那么测试代码还可以再简单一点:
我要说话

describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(function(err) {
if (err) throw err;
done();
});
});
});
});

我要说话

promise代码测试

如果异步模块并不是使用callback,而是使用promise来返回结果的时候,可以让用例函数返回一个promise对象来进行正确性判断,像下面这样:
我要说话

beforeEach(function() {
return db.clear()
.then(function() {
return db.save([tobi, loki, jane]);
});
});

describe('#find()', function() {
it('respond with matching records', function() {
return db.find({ type: 'User' }).should.eventually.have.length(3);
});
});

我要说话

后边还会再提到这种情况我要说话

不建议使用箭头函数

不建议在mocha测试框架中使用箭头函数。箭头函数语法中对this的绑定让会用例函数没办法访问Mocha框架上下文中定义的一些函数,例如this.timeout(1000)在箭头函数中就无法得到正确的结果。
我对这里的理解是:mocha会把用例函数注册到自身的某个属性中,通过属性调用的使用,正常函数可以访问到mocha的其他属性,但是箭头函数不行,就像下面的代码一样:
我要说话

function getTest(){
this.a=555;
var test={
a:1,
b:function(){
console.log(this.a)
},
c:()=>{
console.log(this.a);
}
}
return test;
}
var test=getTest();
test.b();
test.c();

我要说话

输出结果是
1
555我要说话

mocha提供4种钩子函数:before()after()beforeEach()afterEach(),这些钩子函数可以用来在用例集/用例函数开始执行之前/结束执行之后,进行一些环境准备或者环境清理的工作。
我要说话

describe('hooks', function() {

before(function() {
// runs before all tests in this block
});

after(function() {
// runs after all tests in this block
});

beforeEach(function() {
// runs before each test in this block
});

afterEach(function() {
// runs after each test in this block
});

// test cases
});

我要说话

钩子函数的描述参数

定义钩子函数的时候,可以传第一个可选参数作为钩子函数的描述,可以帮助定位用例中的错误信息。若没有穿第一个参数,使用一个非匿名函数作为钩子函数,那么函数名称就将被作为钩子函数的描述。
我要说话

beforeEach(function() {
// beforeEach hook
});

beforeEach(function namedFun() {
// beforeEach:namedFun
});

beforeEach('some description', function() {
// beforeEach:some description
});

我要说话

异步的钩子函数

钩子函数不仅能是同步函数,也可能是异步的函数,就像前边的异步测试用例函数一样。如果我们在开始之前,需要做一些异步的操作,例如在数据库里边准备一些模拟数据,就需要用到这种场景了:
我要说话

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

我要说话

前边讲的钩子函数都是定义在用例集函数里边的,如果在用例集函数之外定义钩子函数,那么这个钩子函数将会对所有的mocha单元测试用例生效。若编写了多个用例集js文件,无论在哪一个用例集文件中,用例集函数之外定义钩子函数,都会对所有用例函数生效。
前边讲到,用例集函数是可以嵌套的,而mocha会生成一个包在最外面的describe函数,把所有的用例集包含起来,那么在其中定义的钩子函数也就对所有的用例函数生效了~
我要说话

beforeEach(function() {
console.log('before every test in every file');
});

我要说话

延迟启动测试

如果想在mocha命令运行之后,先做一些别的工作,再启动测试,可以使用mocha --delay命令,此命令会在全局环境中生成一个run函数,延迟工作完成后调用run函数即可启动测试。
我要说话

setTimeout(function() {
// do some setup

describe('my suite', function() {
// ...
});

run();
}, 5000);

我要说话

测试用例TODO

可以编写一个等待被实现的测试用例,在报告里边也会有提示
我要说话

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

我要说话

2 passing (11ms)
 1 pending

仅执行一个用例集/用例

在用例集函数或者用例函数后边添加.only()可以让mocha只执行此用例集或用例
我要说话

describe('Array', function() {
describe.only('#indexOf()', function() {
// ...
});
});

我要说话

Array用例集下面的嵌套集合,只有#indexOf用例集会被执行
我要说话

describe('Array', function() {
describe('#indexOf()', function() {
it.only('should return -1 unless present', function() {
// ...
});

it('should return the index when present', function() {
// ...
});
});
});

我要说话

这种写法,#indexOf用例集下面的用例,只有第一个加了only的会被执行。
注意:在同一用例集下有多个only标记,mocha会报错。 我要说话

跳过哪些用例集/用例

和加上.only相反,在用例集函数或者用例函数后边加.skip(),可以跳过此用例集或用例的执行。跳过的用例会被标记为pending的用例,在报告中也会作为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() {
// ...
});
});
});

我要说话

跳过用例。
对于一些作废的用例,按我们以往的做法可能就是把它注释掉,mocha推荐的做法是给它们加上skip标记。 我要说话

除了使用添加skip标记之外,mocha还允许在用例执行的过程中跳过此用例,例如用例执行需要某些上下文环境,但是执行的时候发现这些环境并没有准备好,此时就可以调用skip函数跳过此用例:
我要说话

it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
this.skip();
}
});

我要说话

上面被跳过的用例同样会在测试报告中以pending的形式体现出来。为了避免测试逻辑混乱,在调用skip函数之后,就不要再再用例函数或after钩子中执行更多的逻辑了。 我要说话

这里要说明一点,在一个用例函数中,不要存在一个逻辑分支啥也不做,直接让整个用例函数结束,这样是不科学的。用例函数中应该至少使用断言做一个判断,或者调用skip函数跳过用例。
我要说话

it('should only test in the correct environment', function() {
if (/* check test environment */) {
// make assertions
} else {
// do nothing
}
});

我要说话

这样的用例如果走到了do nothing逻辑,在报告中会被标记为pass。比较推荐的做法是,在before钩子函数中检查测试需要的上下文环境,不具备则跳过。
我要说话

before(function() {
if (/* check test environment */) {
// setup code
} else {
this.skip();
}
});

我要说话

重新执行用例

你可以指定让一个失败的用例重新执行一定次数。这个特性是为做end-to-end测试(功能性测试/Selenium测试)而设计的,这些测试数据不好模拟。 mocha是不推荐用这个特性来做单元测试的。 我要说话

这个特性会重新运行用例函数的beforeEach和afterEach钩子函数,但是不会重新运行before和after钩子函数。我要说话

下面是一个重新执行的例子:
我要说话

describe('retries', function() {
// Retry all tests in this suite up to 4 times
this.retries(4);

beforeEach(function () {
browser.get('http://www.yahoo.com');
});

it('should succeed on the 3rd try', function () {
// Specify this test to only retry up to 2 times
this.retries(2);
expect($('.foo').isDisplayed()).to.eventually.be.true;
});
});

我要说话

动态生成用例

mocha可以使用Function.prototype.call和函数表达式来定义用例集和用例,它们可以用来直接动态生成一些测试用例,而不需要使用其他额外的语法。
和你可能在其他框架中见到的一样,这个特性可以实现通过定义一些参数来实现测试用例的功能。
我要说话

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

我要说话

上面的测试会生成下面这样报告:
add()
✓ correctly adds 2 args
✓ correctly adds 3 args
✓ correctly adds 4 args我要说话

许多测试报告会展示测试时间,同样也会标记出那些用例耗时比较长:
1469587478096.png我要说话

可能对于某些测试用例,耗时就是会比较长,那么耗费多长时间才应该本认为执行耗时过长呢? 可以通过slow()函数来标记一下:
我要说话

describe('something slow', function() {
this.slow(10000);

it('should take long enough for me to go make a sandwich', function() {
// ...
});
});

我要说话

用例集执行超时

在用例集下定义的timeout超时会对此用例集下定义的所有嵌套的用例集和用例生效,如果嵌套的用例集或者用例重写了timeout时间,则会覆盖上层的设置。通过this.timeout(0),可以关掉用例或用例集的超时判断。
我要说话

describe('a suite of tests', function() {
this.timeout(500);

it('should take less than 500ms', function(done){
setTimeout(done, 300);
});

it('should take less than 500ms as well', function(done){
setTimeout(done, 250);
});
})

我要说话

用例执行超时

it('should take less than 500ms', function(done){
this.timeout(500);
setTimeout(done, 300);
});

钩子函数超时

describe('a suite of tests', function() {
beforeEach(function(done) {
this.timeout(3000); // A very long environment setup.
setTimeout(done, 2500);
});
});

钩子函数同样可以通过this.timeout(0)来关闭超时判断。我要说话

diff差异比较功能

若断言库抛出了AssertionErrors,且错误对象中有err.expected属性和err.actual属性,mocha会尝试在报告中展示期望的值和得到的值的差异:
1469588275973.png我要说话

mocha使用命令和参数

mocha init 初始化浏览器中测试

mocha init命令用来生成一个浏览器中单元测试的架子。
新建一个目录test
1469588933550.png
在同级目录运行命令 mocha init test ,可以看到test目录下生成了一些样式表文件和js脚本,以及一个用来运行用例、展示报告的index.html
1469589018406.png
接着使用文章开头的chai断言库,此时需要用script标签引入了,于是在index.html中加上
我要说话

<script src="http://chaijs.com/chai.js"></script>

我要说话

index.html内容如下:
我要说话

<!DOCTYPE html>
<html>
<head>
<title>Mocha</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="mocha.css" />
</head>
<body>
<div id="mocha"></div>
<script src="http://chaijs.com/chai.js"></script>
<script src="mocha.js"></script>
<script>mocha.setup('bdd');</script>
<script src="tests.js"></script>
<script>
mocha.run();
</script>
</body>
</html>

我要说话

test.js是一个空文件,等待我们去编写用例,在其中加上:
我要说话

var assert = chai.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));
});
});
});

我要说话

在浏览器中打开index.html,可以看到用例执行报告:
1469589261302.png我要说话

mocha命令参数

mocha命令的基本格式是:mocha [debug] [options] [files]
options包括下面这些,我翻译了一部分目前能理解的
我要说话

-h, --help                              输出帮助信息    
-V, --version                           输出mucha版本    
-A, --async-only                        强制让所有测试用例必须使用callback或者返回promise的方式来异步判断正确性    
-c, --colors                            启用报告中颜色    
-C, --no-colors                         禁用报告中颜色    
-G, --growl                             enable growl notification support    
-O, --reporter-options <k=v,k2=v2,...>  reporter-specific options    
-R, --reporter <name>                   specify the reporter to use    
-S, --sort                              排序测试文件    
-b, --bail                              bail after first test failure    
-d, --debug                             enable node's debugger, synonym for node --debug
-g, --grep <pattern>                    只执行满足 <pattern>格式的用例    
-f, --fgrep <string>                    只执行含有 <string> 的用例    
-gc, --expose-gc                        展示gc回收的log    
-i, --invert                            让 --grep 和 --fgrep 的匹配取反    
-r, --require <name>                    require一下<name>指定的模块    
-s, --slow <ms>                         指定slow时间(单位ms,默认75ms)    
-t, --timeout <ms>                      指定超时时间(单位ms,默认2000ms)    
-u, --ui <name>                         指定user-interface (bdd|tdd|exports)    
-w, --watch                             观察用例文件变化,并重新执行    
--check-leaks                           检测未回收global变量泄露    
--compilers <ext>:<module>,...          用指定的模块来编译文件    
--debug-brk                             启用node的debug模式    
--delay                                 等待异步的用例集(见前边的)    
--es_staging                            enable all staged features    
--full-trace                            display the full stack trace    
--globals <names>                       allow the given comma-delimited global [names]    
--harmony                               enable all harmony features (except typeof)    
--harmony-collections                   enable harmony collections (sets, maps, and weak maps)    
--harmony-generators                    enable harmony generators    
--harmony-proxies                       enable harmony proxies    
--harmony_arrow_functions               enable "harmony arrow functions" (iojs)    
--harmony_classes                       enable "harmony classes" (iojs)    
--harmony_proxies                       enable "harmony proxies" (iojs)    
--harmony_shipping                      enable all shipped harmony features (iojs)    
--inline-diffs                          显示预期和实际结果的string差异比较    
--interfaces                            display available interfaces    
--no-deprecation                        silence deprecation warnings    
--no-exit                               require a clean shutdown of the event loop: mocha will not call process.exit    
--no-timeouts                           禁用timeout,可通过--debug隐式指定    
--opts <path>                           定义option文件路径    
--prof                                  显示统计信息    
--recursive                             包含子目录    
--reporters                             展示可用报告    
--retries                               设置失败用例重试次数    
--throw-deprecation                     每次调用deprecated函数的时候都抛出一个异常    
--trace                                 显示函数调用栈    
--trace-deprecation                     启用的时候显示调用栈    
--watch-extensions <ext>,...            --watch监控的扩展

我要说话

下面是官方文档对部分命令的详细说明:我要说话

-W, –WATCH

用例一旦更新立即执行我要说话

–COMPILERS

例如--compilers coffee:coffee-script编译CoffeeScript 1.6,或者--compilers coffee:coffee-script/register编译CoffeeScript 1.7+我要说话

-B, –BAIL

如果只对第一个抛出的异常感兴趣,可以使用此命令。我要说话

-D, –DEBUG

开启nodejs的debug模式,可以在debugger语句处暂停执行。我要说话

–GLOBALS

names是一个以逗号分隔的列表,如果你的模块需要暴露出一些全局的变量,可以使用此命令,例如mocha --globals app,YUI
这个命令还可以接受通配符,例如--globals '*bar。参数传入 * 的话,会忽略所有全局变量。我要说话

–CHECK-LEAKS

默认情况下,mocha并不会去检查应用暴露出来的全局变量,加上这个配置后就会去检查,此时某全局变量如果没有用上面的–GLOBALS去配置为可接受,mocha就会报错我要说话

-R, –REQUIRE

这个命令可以用来引入一些依赖的模块,比如should.js等,这个命令相当于在测试目录下每个js文件头部运行一下require('should.js'),模块中对Object、Array等对象的扩展会生效,也可以用--require ./test/helper.js这样的命令去引入指定的本地模块。
但是… 很鸡肋的是,如果要引用模块导出的对象,还是需要require,var should = require('should')这样搞。我要说话

-U, –UI

–ui选项可以用来指定所使用的测试接口,默认是“bdd”我要说话

-R, –REPORTER

这个命令可以用来指定报告格式,默认是“spec”。可以使用第三方的报告样式,例如:
npm install mocha-lcov-reporter,--reporter mocha-lcov-reporter我要说话

-T, –TIMEOUT

用来指定用例超时时间我要说话

-S, –SLOW

用来指定慢用例判定时间,默认是75ms我要说话

-G, –GREP

grep pattern可以用来筛选要执行的用例或用例集,pattern参数在mocha内部会被编译成一个正则表达式。
假如有下面的测试用例:
我要说话

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() {
// ...
});
});
});

我要说话

可以用--grep api--grep app--grep users--grep GET,来筛选出要执行的用例。我要说话

测试接口类型

mocha的测试接口类型指的是集中测试用例组织模式的选择,包括BDD行为驱动开发(Behavior Driven Development),TDD测试驱动开发(Test-Driven Development),Exports,QUnit 和 Require-style 几种。我要说话

BDD测试接口提供 describe(), context(), it(), specify(), before(), after(), beforeEach(), 和 afterEach()几种函数,其中context函数只是describe函数的别名,specify函数也是if函数的别名。
mocha默认的测试接口,前边的所有例子都是基于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);
});
});
});
});

我要说话

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

我要说话

EXPORTS

Exports 的写法有的类似于Mocha的前身expresso,其写法如下:
我要说话

module.exports = {
before: function() {
// ...
},

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

我要说话

通过exports导出的对象里边,除了几个钩子函数之外,其他的Object类型属性都是用例集,function类型的属性都是用例。我要说话

QUNIT

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

我要说话

REQUIRE

require测试接口允许你通过require来导入describe函数,取个任意的别名。如果你不希望测试中出现全局的变量,这个接口也是十分有用的。
值得注意的是,这里的require不能直接通过node命令来执行,node的模块管理是不能解析这里的require的,需要通过mocha命令来运行。
我要说话

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

我要说话

测试报告视图

如果不自己加上自定义的报告输出,mocha会在控制台中输出报告。我要说话

SPEC视图

这个是默认的报告样式,输出一个嵌套的分级视图
1469688423629.png我要说话

DOT MATRIX视图

用一系列点点来表示用例,测试的是红点,未实现的是蓝点,比较慢的是黄点,通过的是白点,如果你想让报告看起来简洁一些,可以用这个视图。
1469688537169.png我要说话

NYAN视图

尼玛这是个毛线视图啊,官方文档都懒得给出说明
1469688604402.png我要说话

TAP视图

1469688672698.png我要说话

LANDING STRIP视图

‘Landing Strip’的意思是飞机降落跑道,这是一个逗逼测试人员弄出来的,像一架飞机降落一样的视图。
1469688878574.png
这个是坠机了的视图……
1469688898981.png我要说话

LIST视图

一个简单的列表视图
1469688935839.png我要说话

PROGRESS视图

包含一个简单的进度条的视图
1469688957850.png我要说话

JSON视图

输出一个JSON作为测试结果
1469689152790.png我要说话

##JSON STREAM视图
输出的也是一个JSON,只不过输出的时候会带上换行
1469689235837.png我要说话

JSONCOV覆盖率报告

一个依赖 node-jscoverage 模块生成的视图,用来生成覆盖率报告我要说话

HTMLCOV覆盖率报告

用来生成一个覆盖率的html报告
https://github.com/expressjs/express/commit/b6ee5fafd0d6c79cf7df5560cb324ebee4fe3a7f我要说话

MIN视图

只显示总体测试情况
1469698473893.png我要说话

DOC视图

生成一个只包含html的body部分的报告,结构如下:
1469698544399.png
例如,测试代码如下:
我要说话

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>

我要说话

自己添加head、html等标签,再加上style,可以生成自定义样式的报告。我要说话

MARKDOWN视图

生成一个markdown版本的报告,例子:https://github.com/senchalabs/connect/blob/90a725343c2945aaee637e799b1cd11e065b2bff/tests.md我要说话

HTML视图

目前只有在浏览器中运行的mocha才能直接生成html报告,nodejs中可以通过doc视图或者markdown视图得到的内容自己用脚本生成html版本的~
1469698980933.png我要说话

第三方报告生成器

mocha允许我们自己定义第三方的报告生成器,可以参考文档
一个例子:TeamCity reporter我要说话

在浏览器中运行mocha

mocha项目下都会有mocha.js和mocha.css供浏览器中的测试使用我要说话

只能在浏览器中使用的函数

mocha.allowUncaught() ,未捕获的错误不会被抛出
下面是一个例子,在加载测试脚本之前,用mocha.setup('bdd')函数把测试模式设置为BDD接口,测试脚本加载完之后用mocha.run()函数来运行测试
我要说话

<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>

我要说话

浏览器中可以通过在url后边加?grep=api参数,来使用grep命令我要说话

浏览器中的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
});

我要说话

浏览器中特有的选项

noHighlighting

如果被设置为true,mocha不会尝试用高亮语法输出测试代码我要说话

MOCHA.OPTS(mocha配置)

在服务端运行的时候,mocha会去加载test目录下的mocha.opts文件,来读取mocha配置项。这个配置文件中的每一行代表一项配置。如果运行mocha命令的时候,带上的配置参数与这个配置文件中的配置冲突的话,以命令中的为准。例如:
–require should
–reporter dot
–ui bdd
上面的配置就会让mocha 引入一下should模块、报告样式设置为dot,并且使用bdd的测试接口。我要说话

test/ 目录

默认情况下,mocha会去当前路径下的去找 ./test/*.js或者./test/*.coffee当做测试文件,所以测试文件应该放在test目录下我要说话

编辑器插件

TEXTMATE、JETBRAINS (IntelliJ IDEA, WebStorm, etc.) 等编辑器均有支持mocha测试的插件,需要使用的话请自行查阅。我要说话

使用mocha的项目示例

这个是官方文档地址:http://mochajs.org/我要说话

本文链接:https://www.zoucz.com/blog/2016/08/02/nodejs-unittest-mochajs/我要说话

☞ 参与评论我要说话


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK