• 学习测试框架Mocha


    学习测试框架Mocha

    注意:是参考阮老师的文章来学的。虽然阮老师有讲解,但是觉得自己敲一遍,然后记录一遍效果会更好点。俗话说,好记性不如烂笔头。

       Mocha 是javascript测试框架之一,可以在浏览器和Node环境下使用,除了Mocha测试框架之外,类似的测试框架还有Jasmine, Karma, Tape等。
    可以使用npm全局安装:如下命令:

    npm install -g mocha

    也可以作为项目的依赖进行安装,如下命令:

    npm install --save-dev mocha

    如下所有的测试代码在github上,请查看github上的代码

    Mocha的作用是运行测试脚本,我们先来编写一个js代码吧,下面是一个简单的加法模块 add.js代码:

    function add(x, y) {
      return x + y;
    }
    module.exports = add;

    要测试上面的代码是否对的,因此就要编写测试脚本,测试脚本与所要测试的源码脚本同名,但是后缀名为 .test.js或 .spec.js, 如:xx.test.js 或 xx.spec.js,比如上面的add.js的测试脚本可以叫 add.test.js 或 add.spec.js,因此我们可以在add.js的同目录下新建 add.test.js,(可以查看demo1文件代码)
    编写代码如下:

    var add = require('./add.js');
    var expect = require('chai').expect;
    
    describe('加法函数的测试', function() {
      it('1加1应该等于2', function() {
        expect(add(1, 1)).to.be.equal(2);
      });
    });

    如上代码就是一个测试脚本代码,测试脚本可以包含一个或多个describe块,describe块称为 "测试套件",表示一组相关的测试,它是一个函数,有两个参数,第一个参数是测试套件的名称,第二个参数是一个实际执行的函数。

    每个describe块也可以包含一个或多个it块,it块称为 "测试用例",表示一个单独的测试,是测试的最小单位,它也是一个函数,第一个参数也是测试用例的名称,第二个参数是一个实际执行的函数。

    二. 理解断言库
    断言库可以理解为比较函数,也就是断言函数是否和预期一致,如果一致则表示测试通过,如果不一致表示测试失败。mocha本身是不包括断言库的,所以必须引入第三方断言库的,目前比较受欢迎的断言库有 should.js, expect.js, chai.
    should.js BDD风格
    expect.js expect风格的断言
    chai expect(), assert() 和 should的断言
    Mocha默认使用的是BDD的风格。expect和should都是BDD的风格,二者使用相同的链式语言来组织断言的,但不同在于他们初始化断言的方式,expect使用
    构造函数来创建断言对象实例,而should通过为 Object.prototype新增方法来实现断言(should不支持IE),expect直接指向 chai.expect,
    should则是 chai.should();

    上面的代码中 expect 是断言的意思,该作用是判断源码的实际执行结果与预期结果是否一致,如果不一致就抛出一个错误,因此在执行上面代码之前,
    我们需要在项目中安装 chai, 如下命令:

    npm install --save-dev chai

    所有的测试用例(it块)都应该含有一句或多句断言,是编写测试用例的关键,Mocha本身不包含断言,断言是由断言库来实现的,因此需要先引入断言库。
    如下代码:

    var expect = require('chai').expect;

    上面代码是引用 chai 断言库,使用的是 expect断言风格。

    expect 官网API(http://chaijs.com/api/bdd/).

    如下是一些常用的比较;

    // equal 相等或不相等
    expect(4 + 5).to.be.equal(9);
    expect(4 + 5).to.be.not.equal(10);
    expect('hello').to.equal('hello');  
    expect(42).to.equal(42);  
    expect(1).to.not.equal(true);  
    expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' });  
    expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' });
    
    // above 断言目标的值大于某个value,如果前面有length的链式标记,则可以用来判断数组长度或者字符串长度
    expect(10).to.be.above(5);
    expect('foo').to.have.length.above(2);  
    expect([ 1, 2, 3 ]).to.have.length.above(2); 
    类似的还有least(value)表示大于等于;below(value)表示小于;most(value)表示小于等于
    
    // 判断目标是否为布尔值true(隐式转换)
    expect('everthing').to.be.ok;
    expect(1).to.be.ok;  
    expect(false).to.not.be.ok;
    expect(undefined).to.not.be.ok;  
    expect(null).to.not.be.ok; 
    
    // true/false 断言目标是否为true或false
    expect(true).to.be.true;  
    expect(1).to.not.be.true;
    expect(false).to.be.false;  
    expect(0).to.not.be.false;
    
    // null/undefined 断言目标是否为null/undefined
    expect(null).to.be.null;  
    expect(undefined).not.to.be.null;
    expect(undefined).to.be.undefined;  
    expect(null).to.not.be.undefined;
    
    
    // NaN  断言目标值不是数值
    expect('foo').to.be.NaN;
    expect(4).not.to.be.NaN;
    
    // 判断类型大法(可以实现上面的一些例子):a/an
    expect('test').to.be.a('string');
    expect({ foo: 'bar' }).to.be.an('object');
    expect(foo).to.be.an.instanceof(Foo);
    expect(null).to.be.a('null');  
    expect(undefined).to.be.an('undefined');
    expect(new Error).to.be.an('error');
    expect(new Promise).to.be.a('promise');
    
    // 包含关系:用来断言字符串包含和数组包含。如果用在链式调用中,可以用来测试对象是否包含某key 可以混着用。
    expect([1,2,3]).to.include(2);
    expect('foobar').to.contain('foo');
    expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo');
    
    // 判断空值
    expect([]).to.be.empty;
    expect('').to.be.empty;
    expect({}).to.be.empty;
    
    // match
    expect('foobar').to.match(/^foo/);
        
    // exist 断言目标既不是null也不是undefined
    var foo = 'hi' , bar = null, baz;
    expect(foo).to.exist;  
    expect(bar).to.not.exist;  
    expect(baz).to.not.exist;
    
    // within断言目标值在某个区间范围内,可以与length连用
    expect(7).to.be.within(5,10);  
    expect('foo').to.have.length.within(2,4);  
    expect([ 1, 2, 3 ]).to.have.length.within(2,4);
    
    // instanceOf 断言目标是某个构造器产生的事例
    var Tea = function (name) { this.name = name; } , Chai = new Tea('chai');
    expect(Chai).to.be.an.instanceof(Tea);  
    expect([ 1, 2, 3 ]).to.be.instanceof(Array); 
    
    // property(name, [value])  断言目标有以name为key的属性,并且可以指定value断言属性值是严格相等的,此[value]参数为可选,如果使用deep链式调用,可以在name中指定对象或数组的引用表示方法
    // simple referencing
    var obj = { foo: 'bar' };  
    expect(obj).to.have.property('foo');  
    expect(obj).to.have.property('foo', 'bar');// 类似于expect(obj).to.contains.keys('foo')
    
    // deep referencing
    var deepObj = {  
      green: { tea: 'matcha' },
      teas: [ 'chai', 'matcha', { tea: 'konacha' } ]
    };
    expect(deepObj).to.have.deep.property('green.tea', 'matcha');  
    expect(deepObj).to.have.deep.property('teas[1]', 'matcha');  
    expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); 
    
    // ownproperty 断言目标拥有自己的属性,非原型链继承
    expect('test').to.have.ownProperty('length'); 
    
    // throw 断言目标抛出特定的异常
    var err = new ReferenceError('This is a bad function.');  
    var fn = function () { throw err; }  
    expect(fn).to.throw(ReferenceError);  
    expect(fn).to.throw(Error);  
    expect(fn).to.throw(/bad function/);  
    expect(fn).to.not.throw('good function');  
    expect(fn).to.throw(ReferenceError, /bad function/);  
    expect(fn).to.throw(err);  
    expect(fn).to.not.throw(new RangeError('Out of range.'));  
    
    // satisfy(method) 断言目标通过一个真值测试
    expect(1).to.satisfy(function(num) { return num > 0; })

    三. mocha测试代码如何运行?
    上面的add.test.js 编写完成后,我们需要运行测试代码了,进入add.test.js代码的目录后,执行如下命令可运行:

    mocha add.test.js

    如下结果:

    $ mocha add.test.js
    
    
      加法函数的测试
        ✓ 1加1应该等于2
    
    
      1 passing (10ms)

    如上所示,表示测试脚本通过了测试,共用一个测试用例,耗时10毫秒。

    mocha命令后面也可以指定多个文件,如下命令:

    mocha xx.test.js yy.test.js

    3-1 把测试文件放入test目录下
    mocha默认运行test子目录里面的测试脚本,我们一般情况下,可以把测试脚本放在test目录下,然后进入对应的目录,直接执行mocha命令即可:
    请看demo2;
    如下目录页面:

    demo2
       |---- src
       |  |--- add.js
       |  |--- multiple.js
       |  |--- reduce.js
       |---- test
       |  |--- dir
       |  | |--- multiple.test.js 
       |  |
       |  |--- add.test.js

    src/add.js 代码如下:

    function add(x, y) {
      return x + y;
    }
    module.exports = add;

    src/multiple.js代码如下:

    function multiply(x, y) {
      return x * y;
    }
    module.exports = multiply;

    src/reduce.js 代码如下:

    function add(x, y) {
      return x - y;
    }
    module.exports = add;

    test/add.test.js代码如下:

    var add = require('../src/add.js');
    var expect = require('chai').expect;
    
    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);
      });
    });

    test/dir/multiple.test.js代码如下:

    var multiply = require('../../src/multiply');
    var expect = require('chai').expect;
    
    describe('乘法函数的测试', function() {
      it('1 乘 1 应该等于 1', function() {
        expect(multiply(1, 1)).to.be.equal(1);
      });
    })

    当我在demo2项目目录下,运行 mocha 命令后,执行如下:

    $ mocha
    
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
    
      2 passing (10ms)

    我们可以看到,test子目录里面的测试脚本执行了,但是test目录下还有dir这样的目录里面的测试脚本文件并没有执行,所以我们可以得出一个结论是,mocha
    命令只会执行test第一层目录下所有文件,并不能执行嵌套目录下的文件。
    为了执行所有嵌套目录下的文件,我们可以 mocha命令后面加一个参数 --recursive 参数,如下命令:

    $ mocha --recursive
    
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
      乘法函数的测试
        ✓ 1 乘 1 应该等于 1
    
    
      3 passing (11ms)

    四. 理解使用通配符
    命令行中测试脚本文件,可能会有多个脚本文件需要被测试,这时候我们可以使用通配符,来做批量操作。
    比如我们在 demo2下新建spec目录,文件目录变成如下结构:

    demo2
       |---- src
       |  |--- add.js
       |  |--- multiple.js
       |  |--- reduce.js
       |---- test
       |  |--- dir
       |  | |--- multiple.test.js 
       |  |
       |  |--- add.test.js
       |
       |----- spec
       |  |--- add.js
       |  |--- reduce.js

    demo2/spec/add.js 代码如下:

    var add = require('../src/add.js');
    var expect = require('chai').expect;
    
    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);
      });
    });

    demo2/spec/reduce.js代码如下:

    var reduce = require('../src/reduce.js');
    var expect = require('chai').expect;
    
    describe('减法函数的测试', function() {
      it('2 减 1 应该等于 1', function() {
        expect(reduce(2, 1)).to.be.equal(1);
      });
    });

    我们可以运行如下命令,执行多个测试脚本文件:

    mocha spec/{add,reduce}.js

    命令效果如下:

    $ mocha spec/{add,reduce}.js
    
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
      减法函数的测试
        ✓ 2 减 1 应该等于 1
    
    
      3 passing (11ms)

    或者直接后面加*号,匹配所有的文件,和js中的正则类似:如下命令:

    $ mocha spec/*.js
    
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
      减法函数的测试
        ✓ 2 减 1 应该等于 1
    
    
      3 passing (10ms)

    五. 命令行参数常用的有哪些?
    5.1 --help
    --help参数,用来查看Mocha的所有命令行参数,如下命令所示:
    mocha --help

    5.2 --reporter
    --reporter参数用来指定测试报告的格式,默认是spec格式。

    $ mocha
    # 等同于
    $ mocha --reporter spec

    我们可以使用 mocha --reporters 命令查看所有内置的报告格式。如下命令:

    $ mocha --reporters    
    
        dot - dot matrix
        doc - html documentation
        spec - hierarchical spec list
        json - single json object
        progress - progress bar
        list - spec-style listing
        tap - test-anything-protocol
        landing - unicode landing strip
        xunit - xunit reporter
        min - minimal reporter (great with --watch)
        json-stream - newline delimited json events
        markdown - markdown documentation (github flavour)
        nyan - nyan cat!

    我们可以使用 mochawesome(http://adamgruber.github.io/mochawesome/) 模块,可以生成漂亮的HTML格式的报告。
    首先我们需要安装 mochawesome模块,如下命令行:

    npm install --save-dev mochawesome
    $ ../node_modules/.bin/mocha --reporter mochawesome
    
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
    
      2 passing (10ms)
    
    [mochawesome] Report JSON saved to /Users/tugenhua/个人demo/vue1204/mocha/demo2/mochawesome-report/mochawesome.json
    
    [mochawesome] Report HTML saved to /Users/tugenhua/个人demo/vue1204/mocha/demo2/mochawesome-report/mochawesome.html

    因此会在demo2项目目录下生成 mochawesome-report 文件目录,我们可以查看 mochawesome/mochawesome.html文件打开看一下即可:

    5.3 --watch
    --watch 参数用来监听指定的测试脚本,只要测试脚本有变化,就会自动运行mocha。我们在demo2目录下,运行 mocha --watch命令,
    然后修改脚本文件,可以看到如下:

    $ mocha --watch
    
      加法函数的测试
        ✓ 1 加 1 应该等于 2
        ✓ 任何数加0应该等于自身
    
    
      2 passing (9ms)
    
      加法函数的测试
    111 加 1 应该等于 2
    11
        ✓ 任何数加0应该等于自身
    
    
      2 passing (2ms)

    我在add.js 加了一句 console.log(11),上面可以看到也同样重新执行了 mocha命令。

    5.4 --bail
    --bail参数指定只要有一个测试用例没有通过,就停止执行后面的测试用例。
    mocha --bail

    5.5 --grep
    --grep参数用于搜索测试用例的名称(即it块的第一个参数),然后只执行到匹配的测试用例。
    如下代码命令:

    $ mocha                
    
      加法函数的测试
    111 加 1 应该等于 2
    11
        ✓ 任何数加0应该等于自身
    
    
      2 passing (10ms)
    
    
    ~/个人demo/vue1204/mocha/demo2 on � Dev_20171115_wealth!
    $ mocha --grep "1 加 1"
    
      加法函数的测试
    111 加 1 应该等于 2
    
    
      1 passing (12ms)

    5.6 --invert
    --invert参数表示只运行不符合条件的测试脚本,必须与 --grep参数配合使用。
    如下执行结果:

    ~/个人demo/vue1204/mocha/demo2 on � Dev_20171115_wealth! 
    $ mocha                         
    
      加法函数的测试
    111 加 1 应该等于 2
    11
        ✓ 任何数加0应该等于自身
    
    
      2 passing (13ms)
    
    ~/个人demo/vue1204/mocha/demo2 on � Dev_20171115_wealth! 
    $ mocha --grep "1 加 1" --invert
    
      加法函数的测试
    11
        ✓ 任何数加0应该等于自身
    
      1 passing (10ms)

    六. 配置文件 mocha.opts
    Mocha的测试脚本文件 允许放在test目录下面,但是我们也可以在test目录下新建一个mocha.opts文件,把命令行写在该里面,还是看demo2目录结构,
    在test目录下新建 mocha.opts文件,如下目录结构:

    demo2
       |---- src
       |  |--- add.js
       |  |--- multiple.js
       |  |--- reduce.js
       |---- test
       |  |--- dir
       |  | |--- multiple.test.js 
       |  |
       |  |--- add.test.js
       |  |--- mocha.opts
       |
       |----- spec
       |  |--- add.js
       |  |--- reduce.js

    mocha.opts文件写入如下命令:

    --recursive
    --reporter tap

    然后执行mocha命令,就可以执行测试中的所有测试代码:

    ~/个人demo/vue1204/mocha/demo2 on � Dev_20171115_wealth! 
    $ mocha
    1..3
    11
    ok 1 加法函数的测试 1 加 1 应该等于 2
    11
    ok 2 加法函数的测试 任何数加0应该等于自身
    ok 3 乘法函数的测试 1 乘 1 应该等于 1
    # tests 3
    # pass 3
    # fail 0

    当然如果测试用例不是存放在test子目录下,可以在mocha.opts写入如下内容:

    server-tests
    --recursive
    --reporter tap 

    上面代码指定允许 server-tests 目录及其子目录之中的测试脚本。

    七: ES6的测试;
    如果测试脚本是用ES6编写的,那么允许测试之前,需要先用babel转码,我们在test目录下新建 es6.test.js文件,先看目录结构如下:

    demo2
       |---- src
       |  |--- add.js
       |  |--- multiple.js
       |  |--- reduce.js
       |---- test
       |  |--- dir
       |  | |--- multiple.test.js 
       |  |
       |  |--- add.test.js
       |  |--- es6.test.js
       |  |--- mocha.opts
       |
       |----- spec
       |  |--- add.js
       |  |--- reduce.js

    es6.test.js 代码如下:

    import add from '../src/add.js';
    import chai from 'chai';
    let expect = chai.expect;
    
    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);
      });
    });

    如果我们直接在demo2命令行中允许 mocha命令就会报错,如下报错:

    $ mocha
    /Users/tugenhua/个人demo/vue1204/mocha/demo2/test/es6.test.js:1
    (function (exports, require, module, __filename, __dirname) { import add from '../src/add.js';
                                                                  ^^^^^^
    
    SyntaxError: Unexpected token import

    因此我们需要ES6转码,需要安装Babel。命令如下:

    npm install babel-core babel-preset-es2015 --save-dev

    然后我们需要在项目的目录下,新建一个 .babelrc配置文件。
    添加如下代码如下:

    {
      "presets": ['es2015']
    }

    最后,我们使用 --compilers 参数指定测试脚本的转码器。

    ../node_modules/mocha/bin/mocha --compilers js:babel-core/register

    如上命令代码,--compilers 参数后面是一个使用冒号分割的字符串,冒号左边是文件的后缀名,右边是用来处理这一类文件的模块名,意思是说,先使用
    babel-core/register模块,处理一下 .js文件;如下命令行代码所示:

    ~/个人demo/vue1204/mocha/demo2 on � Dev_20171115_wealth! 
    $ ../node_modules/mocha/bin/mocha --compilers js:babel-core/register
    1..5
    (node:55513) DeprecationWarning: "--compilers" will be removed in a future version of Mocha; see https://git.io/vdcSr for more info
    11
    ok 1 加法函数的测试 1 加 1 应该等于 2
    11
    ok 2 加法函数的测试 任何数加0应该等于自身
    ok 3 乘法函数的测试 1 乘 1 应该等于 1
    11
    ok 4 加法函数的测试 1 加 1 应该等于 2
    11
    ok 5 加法函数的测试 任何数加0应该等于自身
    # tests 5
    # pass 5
    # fail 0

    注意点:Babel默认不会对 Iterator, Generator, Promise, Map, Set等全局对象,以及一些全局对象的方法(比如Object.assign)转码,
    如果我们想要对这些对象转码,我们需要安装 babel-polyfill.

    npm install --save-dev babel-polyfill

    最后,需要在我们的脚本头部加上 如下引入 babel-polyfill代码

    import 'babel-polyfill'

    八,异步测试
    先在mocha项目目录下 新建文件demo3,如下目录结构:

    demo3
      |---- timeout.test.js

    timeout.test.js代码如下:

    var expect = require('chai').expect;
    
    describe('timeout.test.js - 超时测试', function() {
      it('测试应该 5000 毫秒后结束', function(done) {
        var x = true;
        var f = function() {
          x = false;
          expect(x).to.be.not.ok;
          done();
        };
        setTimeout(f, 4000);
      });
    });

    然后在demo3目录下,运行命令行 mocha timeout.test.js, 执行如下:

    ~/个人demo/vue1204/mocha/demo3 on � Dev_20171115_wealth!
    $ mocha timeout.test.js
    
      timeout.test.js - 超时测试
        1) 测试应该 5000 毫秒后结束
    
    
      0 passing (2s)
      1 failing
    
      1) timeout.test.js - 超时测试
           测试应该 5000 毫秒后结束:
         Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.

    可以看到如上报错 Timeout of 2000ms exceeded, 这是因为mocha默认每个测试用例最多执行2000毫秒,如果超过这个时间没有返回结果,就会报错,
    所以我们在进行异步操作的时候,需要额外指定timeout的时间的。因为异步的操作是需要4000毫秒,所以我们指定5000毫秒就不会报错了。
    如下命令:

    mocha --timeout 5000 timeout.test.js

    如下执行结果:

    ~/个人demo/vue1204/mocha/demo3 on � Dev_20171115_wealth! 
    $ mocha --timeout 5000 timeout.test.js
    
      timeout.test.js - 超时测试
        ✓ 测试应该 5000 毫秒后结束 (4008ms)
    
      1 passing (4s)

    这样就保证测试用例成功了。

    Mocha内置对Promise的支持,允许直接返回Promise. 在demo3目录下 新建 promise.test.js, 如下目录结构:

    demo3
      |---- timeout.test.js
      |---- promise.test.js

    promise.test.js 代码如下:

    var fetch = require('node-fetch');
    var expect = require('chai').expect;
    
    describe('promise异步测试', function() {
      it('异步请求应该返回一个对象', function() {
        return fetch("https://api.github.com")
          .then(function(res) {
            return res.json()
          }).then(function(json) {
            expect(json).to.be.an("object");
          })
      })
    });

    然后执行命令如下:

    ~/个人demo/vue1204/mocha/demo3 on � Dev_20171115_wealth!
    $ mocha promise.test.js
    
    
      promise异步测试
        ✓ 异步请求应该返回一个对象 (1165ms)
    
    
      1 passing (1s)

    如上可以看到也是可以成功的。

    九:测试用例的钩子
    Mocha在describe块之中,提供了测试用例的四个钩子,before(), after(), beforeEach()和afterEach(),他们会在指定的时间内执行。

    代码如下:

    describe('hooks', function() {
      before(function(){
        // 在本区块的所有测试用例之前执行
      });
      after(function(){
        // 在本区块的所有测试用例之后执行
      });
      beforeEach(function(){
        // 在本区块的每个测试用例之前执行
      });
      afterEach(function(){
        // 在本区块的每个测试用例之后执行
      });
    });

    before(): 将会在所有测试用例执行之前运行,比如在之前插入数据等等操作。
    after(): 会在所有测试执行之后运行,用于清理测试环境,回滚到清空数据状态。
    beforeEach(): 将会在每个测试用例执行之前执行,可用于测试测试需要准备相关数据的条件。
    afterEach(): 将会在每个测试用例之后执行,可用于准备测试用例所需的后置条件。
    请看如下demo,在来理解下 mocha的四个钩子函数,
    在项目的根目录下 新建demo4,目录结构如下:

    demo4
      |---- src
      |  |-- hooks.js
      |---- test
      |  |--- hooks.test.js

    hooks.js 代码如下:

    // 保存用户对象
    var saveUserObj = {};
    
    // 定义用户类
    function User (name) {}
    
    // 保存用户
    User.save = function(name) {
      saveUserObj[name] = name;
    } 
    
    // 删除用户
    User.delete = function(name) {
      delete saveUserObj[name];
    }
    
    // 检查是否包含该用户
    User.contains = function(name) {
      return saveUserObj[name] !== null;
    }
    // 返回所有的数据
    User.getUsers = function() {
      return saveUserObj;
    }
    module.exports = User;

    hooks.test.js代码如下:

    var should = require('should');
    var User = require('../src/hooks.js');
    
    // 描述User的行为
    describe('描述User的行为', function(){
      // 执行所有测试之前,执行before函数,添加数据
      before(function(){
        User.save('kongzhi111');
        console.log(User.getUsers()); // 打印出{kongzhi111: 'kongzhi111'}
        console.log(111111111111111111111);
      });
      // 在执行每个测试前,执行beforeEach函数,添加数据
      beforeEach(function() {
        User.save('kongzhi222');
        console.log(User.getUsers());
        // 打印出 {kongzhi111: 'kongzhi111', kongzhi222: 'kongzhi222'}
        console.log(222222222222222222222222)
      })
      // 描述User.save的行为
      describe('描述User.save的行为', function() {
        // 保存kongzhi333成功了
        it('保存kongzhi333成功了', function() {
          User.save('kongzhi333');
          console.log(User.getUsers());
          // 打印出 {kongzhi111: 'kongzhi111', kongzhi222: 'kongzhi222', kongzhi333: 'kongzhi333'}
          console.log(33333333333333333333);
        })
      });
      // 描述User.contains的行为
      describe('描述User.contains的行为', function(){
        it('kongzhi111是存在的', function(){
          User.contains('kongzhi111').should.be.exactly(true);
        });
        it('kongzhi222是存在的', function(){
          User.contains('kongzhi222').should.be.exactly(true);
        });
        it('kongzhi333是存在的', function(){
          User.contains('kongzhi333').should.be.exactly(true);
        });
        it('kongzhi555是不存在', function(){
          User.contains('kongzhi555').should.be.exactly(true);
        });
      });
      // 在执行完每个测试后,清空数据
      afterEach(function() {
        User.delete('kongzhi222');
        console.log(User.getUsers());  // 打印 {kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333'}
        console.log(44444444444444444444444);
      });
      // 在执行完每个测试后,清空数据
      after(function() {
        User.delete('kongzhi111');
        console.log(User.getUsers()); // 打印 {kongzhi333: 'kongzhi333'}
        console.log(555555555555555555555555);
        User.delete('kongzhi333');
        console.log(User.getUsers()); // 打印 {}
      });
    })

    在demo4下 运行mocha,执行命令后 如下:

    ~/个人demo/vue1204/mocha/demo4 on � Dev_20171115_wealth!
    $ mocha 
    
      描述User的行为
    { kongzhi111: 'kongzhi111' }
    111111111111111110000
        描述User.save的行为
    { kongzhi111: 'kongzhi111', kongzhi222: 'kongzhi222' }
    2.2222222222222222e+23
    { kongzhi111: 'kongzhi111',
      kongzhi222: 'kongzhi222',
      kongzhi333: 'kongzhi333' }
    33333333333333330000
          ✓ 保存kongzhi333成功了
    { kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333' }
    4.4444444444444445e+22
        描述User.contains的行为
    { kongzhi111: 'kongzhi111',
      kongzhi333: 'kongzhi333',
      kongzhi222: 'kongzhi222' }
    2.2222222222222222e+23
          ✓ kongzhi111是存在的
    { kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333' }
    4.4444444444444445e+22
    { kongzhi111: 'kongzhi111',
      kongzhi333: 'kongzhi333',
      kongzhi222: 'kongzhi222' }
    2.2222222222222222e+23
          ✓ kongzhi222是存在的
    { kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333' }
    4.4444444444444445e+22
    { kongzhi111: 'kongzhi111',
      kongzhi333: 'kongzhi333',
      kongzhi222: 'kongzhi222' }
    2.2222222222222222e+23
          ✓ kongzhi333是存在的
    { kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333' }
    4.4444444444444445e+22
    { kongzhi111: 'kongzhi111',
      kongzhi333: 'kongzhi333',
      kongzhi222: 'kongzhi222' }
    2.2222222222222222e+23
          ✓ kongzhi555是不存在
    { kongzhi111: 'kongzhi111', kongzhi333: 'kongzhi333' }
    4.4444444444444445e+22
    { kongzhi333: 'kongzhi333' }
    5.5555555555555555e+23
    {}

    可以看到如上测试结果后的运行,试着理解一下,应该可以理解mocha中的4各钩子函数的含义了。

    理解异步钩子函数

    在demo4目录下的test文件下 新建 hooks-async.test.js 用于测试异步的代码

    demo4
      |---- src
      |  |-- hooks.js
      |---- test
      |  |--- hooks.test.js
      |  |--- hooks-async.test.js

    hooks-async.test.js 代码如下:

    var expect = require('chai').expect;
    describe('异步钩子函数', function() {
      var foo = false;
      beforeEach(function(){
        setTimeout(function(){
          foo = true;
        }, 50)
      });
      it('异步钩子函数成功', function() {
        expect(foo).to.be.equal(true);
      })
    });

    运行结果如下:

    异步钩子函数
           异步钩子函数成功:
    
          AssertionError: expected false to equal true
          + expected - actual
    
          -false
          +true

    如上可以看到测试失败,原因是因为setTimeout 是异步的,在setTimeout执行完之前,it函数已经被执行了,所以foo当时数据还是false,
    因此false不等于true了。

    这时候 done参数出来了,在回调函数存在时候,它会告诉mocha,你正在编写一个异步测试,会等到异步测试完成的时候来调用done函数。
    或者超过2秒后超时,如下代码就可以成功了;
    hooks-async.test.js 代码如下:

    var expect = require('chai').expect;
    describe('异步钩子函数', function() {
      var foo = false;
      beforeEach(function(done){
        setTimeout(function(){
          foo = true;
          // complete the async beforeEach
          done();
        }, 50)
      });
      it('异步钩子函数成功', function() {
        expect(foo).to.be.equal(true);
      });
    });

    10. 理解测试用例的管理
    一个脚本中可能有很多测试用例,有时候,我们想只运行其中的几个,这时候我们使用only方法。describe块和it块都允许调用only方法,
    表示只运行某个测试套件或测试用例。
    在项目中新建文件demo5,结构如下:

    demo5
      |---- src
      |  |-- add.js
      |---- test
      |  |--- add.test.js

    add.test.js 代码如下:

    var expect = require('chai').expect;
    var add = require('../src/add.js');
    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);
    });

    进入demo5目录,运行mocha命令后,如下:

    ~/个人demo/vue1204/mocha/demo5 on � Dev_20171115_wealth!
    $ mocha
    
    
      ✓ 1 加 1应该等于2
    
      1 passing (8ms)

    可以看到只运行了 only方法。

    十一:浏览器测试
    除了在命令行运行,mocha还可以在浏览器下运行。
    首先,使用 mocha init 命令在在指定的目录生成初始化文件。
    mocha init demo6
    在mocha目录下 运行上面的命令后,会在demo6生成 index.html. mocha.css, mocha.js 和 tests.js 文件。
    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="mocha.js"></script>
        <script>mocha.setup('bdd');</script>
        <script src="tests.js"></script>
        <script>
          mocha.run();
        </script>
      </body>
    </html>

    然后在demo6 下 新建一个 src/add.js 文件
    代码如下:

    function add(x, y) {
      return x + y;
    }

    然后,把这个文件,以及断言库chai.js,加入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 type="text/javascript" src="src/add.js"></script>
        <script type="text/javascript" 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>

    然后在 tests.js 添加如下代码:

    var expect = chai.expect;
    
    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-demo项目内 新建demo7文件,该目录文件存放如下文件
    如下目录页面:

    demo7
       |---- src
       |  |--- add.js
       |  |--- multiple.js
       |---- test
       |  |--- dir
       |  | |--- multiple.test.js 
       |  |
       |  |--- add.test.js

    进入demo7目录,运行如下命令:

    $ mocha --recursive -R markdown >spec.md

    就会在该目录下 生成 spec.md 文件,-R markdown参数指定规格报告是markdown格式。
    如果想生成HTML格式的报告spec.html,使用下面的命令。

    $ mocha --recursive -R doc > spec.html

    就会在该目录下 生成 spec.html文件。

    git上查看demo源码

  • 相关阅读:
    腾讯课堂目标2017初中数学联赛集训队作业题解答-8
    2016猿辅导初中数学竞赛训练营作业题解答-10
    2016猿辅导初中数学竞赛训练营作业题解答-9
    2016猿辅导初中数学竞赛训练营作业题解答-8
    分类讨论的经典之作: 一道烧脑的数学竞赛压轴题解法赏析
    腾讯课堂目标2017初中数学联赛集训队作业题解答-7
    2016猿辅导初中数学竞赛训练营作业题解答-7
    腾讯课堂目标2017初中数学联赛集训队作业题解答-6
    正则:千分位
    为什么vue中的data用return返回呢?
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/8419534.html
Copyright © 2020-2023  润新知