zoukankan      html  css  js  c++  java
  • 使用mocha测试

     

    学习了MOCHA官网的示例,将学习成果记录一下。【原文+例子:使用mocha测试

     

    mocha是什么

    Mocha是一个跑在node和浏览器上的javascript测试框架,让异步测试变得简单有趣, 并提供灵活精确的报告。

    安装

    使用npm全局安装

    $ npm install --global mocha
    

    作为项目开发依赖安装

    $ npm install --save-dev mocha
    

    开始

    创建测试文件learn-mocha

    $ npm install mocha -g // 全局安装mocha
    $ mkdir test // 创建test文件夹
    $ touch test.js // 创建test文件
    

    例子

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

    例子中使用了测试集定义函数describe()和测试用例定义函数it(),先引入nodeassert模块的eaual()方法用来验证两数是否相等:[1,2,3].indexOf(4) == -1

    learn-mocha git:(master) ✗ mocha
    
      Array
        #indexOf()
          ✓ should return -1 when the value is not present
    
      1 passing (7ms)
    

    在终端输入mocha,可以看到测试用例通过了。

    Mocha的执行会找到当前命令执行目录下的test目录。./test/*.jsMocha寻找的目标。 也可以在package.json中设置如下设置,就可以使用npm test命令行开启Mocha测试

    "scripts": {
      "test": "mocha"
    }
    

    断言ASSERTIONS

    Mocha支持各种断言库来验证功能,例如should.js、chai、expect.js、better-assert、unexpected等

    异步模式

    在mocha中测试异步代码并不容易。通过给it()加一个回调函数(通常命名为done),mocha将会知道异步代码执行之后需要调用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) done(err);
            else done();
          });
        });
      });
    });
    

    当done()可以接受异步代码错误的时候,上面代码还可以简化为

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

    使用PROMISES

    除了使用回调函数done(), 你还可以返回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);
      });
    });
    

    使用async/await

    如果js环境支持 async/await, 你可以这样写异步测试

    beforeEach(async function() {
      await db.clear();
      await db.save([tobi, loki, jane]);
    });
    
    describe('#find()', function() {
      it('responds with matching records', async function() {
        const users = await db.find({ type: 'User' });
        users.should.have.length(3);
      });
    });
    

    同步模式

    当测试同步代码时,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中使用箭头函数,因为箭头函数对this的绑定会使测试用例无法访问Mocha上下文中的一些方法。

    describe('my suite', () => {
      it('my test with arrow function', () => {
        // should set the timeout of this test to 1000 ms; instead will fail
        this.timeout(1000);
        assert.ok(true);
      });
    });
    
    describe('my suite', function () {
      it('my test without arrow function', function() {
        // set the timeout of this test to 1000 ms; passing
        this.timeout(1000);
        assert.ok(true);
      });
    });
    

    HOOKS

    Mocha提供了四种hooks用来做测试准备和测后清理工作

    • before() 在所有测试套件运行之前运行
    • after() 在所有测试套件运行之后运行
    • beforeEach() 在每个测试用例运行之前运行
    • afterEach() 在每个测试用例运行之后运行
    var assert = require('assert');
    describe('hooks', function() {
    
      before(function() {
        console.log('runs before all tests in this block') 
      });
    
      after(function() {
        console.log('runs after all tests in this block') 
      });
    
      beforeEach(function() {
        console.log('runs before each test in this block') 
      });
    
      afterEach(function() {
        console.log('runs after each test in this block') 
      });
    
      it('test 1', function(){
        assert.ok(true)
      })
    
      it('test 2', function(){
        assert.ok(true)
      })
    
    });
    
    ➜  learn-mocha git:(master) ✗ mocha test/hooks.js
    
      hooks
    runs before all tests in this block
    runs before each test in this block
        ✓ test 1
    runs after each test in this block
    runs before each test in this block
        ✓ test 2
    runs after each test in this block
    runs after all tests in this block
    
      2 passing (8ms)
    

    描述HOOKS

    任何钩子在回调前都有一个可选的描述,在测试中能更简单定位到错误。如果一个钩子是命名函数,在没有描述时,将会使用函数名。

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

    异步HOOKS

    所有hooks(before(), after(), beforeEach(), afterEach()) 都有可能是同步或者异步,就像一个常规的测试。例如,您可能希望在每个测试之前填充虚拟内容的数据库:

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

    延迟根suite

    如果你需要在所有suites运行之前执行异步操作,你可能会延迟根suite。用--delay运行mocha。这将把一个特殊的回调函数,run()附加到全局上下文中:

    setTimeout(function() {
      // do some setup
    
      describe('my suite', function() {
        // ...
      });
    
      run();
    }, 5000);
    

    待定测试(PENDING TESTS)

    待定测试将包括在测试结果中,并且标记为pending。未决测试不被认为是失败的测试。不添加回调函数callback即可。

      describe('#indexOf()', function() {
        // pending test below
        it('should return -1 when the value is not present');
      });
    });
    
    learn-mocha git:(master) ✗ mocha test/pending.js
    
      Array
        #indexOf()
          - should return -1 when the value is not present
    
      0 passing (5ms)
      1 pending
    

    it()中没有回调函数,就会显示 0 passing 1 pending

    独有测试(EXCLUSIVE TESTS)

    可以通过添加.only()describe()it()函数中,来指定测试套件。测试套件和测试用例可以多次定义。如果在测试套件和测试用例同时都加上了.only()的时候,测试用例的执行是优先的。例如suite 2中,只执行了test case 5

    const assert = require('assert')
    
    describe('suite 1', function () {
    
      describe('sub suite 1', function () {
    
        it('test case 1', function () {
          assert(true)
        })
    
        it('test case 2', function () {
          assert(true)
        })
      })
    
      describe.only('sub suite 2', function () {
    
        it('test case 3', function () {
          assert(true)
        })
      })
    })
    
    describe.only('suite 2', function () {
      it('test case 4', function () {
        assert(true)
      })
    
      it.only('test case 5', function () {
        assert(true)
      })
    })
    
    ➜  learn-mocha git:(master) ✗ mocha test/exclusive.js
    
      suite 1
        sub suite 2
          ✓ test case 3
    
      suite 2
        ✓ test case 5
    
      2 passing (7ms) (5ms)
    

    跳过测试(INCLUSIVE TESTS)

    与 .only() 相反,通过给describe()it()加上.skip(), mocha 会忽略这些测试套件或者测试用例。这些被跳过的测试都会被标记为pending

    const assert = require('assert')
    
    describe('suite 1', function () {
    
      describe('sub suite 1', function () {
    
        it('test case 1', function () {
          assert(true)
        })
    
        it('test case 2', function () {
          assert(true)
        })
      })
    
      describe.skip('sub suite 2', function () {
    
        it('test case 3', function () {
          assert(true)
        })
      })
    })
    
    describe.skip('suite 2', function () {
      it('test case 4', function () {
        assert(true)
      })
    
      it.skip('test case 5', function () {
        assert(true)
      })
    })
    
    let checkTestEnviroment = false
    describe('suite 3', function () {
      it('test case 6', function () {
        if (checkTestEnviroment) { 
          assert(true)
        } else {
          this.skip()
        }
      })
    
      it('test case 7', function () {
        assert(true)
      })
    })
    

    从执行结果来看,test case 3 和 suite 2 和 test case 6 套件都进入了 pending 待定状态。 test case 3 是因为测试用例 it.skip 。 suite 2 是因为测试套件 describe.skip 。 test case 6 是因为使用了 this.skip() ,模拟环境 checkTestEnviroment 有问题,需要跳过测试,最后跳过的测试会被标记为 pending 。

    ➜  learn-mocha git:(master) ✗ mocha test/inclusive.js
    
      suite 1
        sub suite 1
          ✓ test case 1
          ✓ test case 2
        sub suite 2
          - test case 3
    
      suite 2
        - test case 4
        - test case 5
    
      suite 3
        - test case 6
        ✓ test case 7
    
      3 passing (9ms)
      4 pending
    

    使用 .skip() 是比注释更好的能够不执行指定测试的方法。

    重跑测试(RETRY TESTS)

    可以选择 this.retries(number) 来重新执行失败的测试到一定的次数。这个函数是为了处理资源不容易被模拟和截断的 end-to-end 测试而设计的,所以不推荐在单元测试里使用。

    this.retries(number) 作用在 beforeEach/afterEach hooks中,但是不作用在 before/after hooks中。

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

    动态生成测试(DYNAMICALLY GENERATING TESTS)

    mocha 使用 Function.prototype.call 和函数表达式来定义测试套件和测试用例,这样能简单动态的生成测试用例。不需要特别的语法,只需 javascirpt 就能实现类似参数化测试的功能。

    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);
        });
      });
    });
    
    ➜  learn-mocha git:(master) ✗ mocha test/dynamically-generate.js
    
      add()
        ✓ correctly adds 2 args
        ✓ correctly adds 3 args
        ✓ correctly adds 4 args
    
      3 passing (11ms)
    

    测试持续时间(TEST DURATION)

    在许多测试报告里会显示测试时间,当测试时间过长,会被特殊标记出来。可以使用 slow() 方法,来定义被认为 slow 的测试时间长度。

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

    测试超时(TIMEOUTS)

    套件级别(SUITE-LEVEL)

    在套件级别describe()定义this.timeout(numer),将会被运用于该套件下的所有嵌套套件和测试用例。

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

    上面的代码定义了超时时间是500ms,然后测试执行时间都没有超过,所以测试可以通过

    ➜  learn-mocha git:(master) ✗ mocha test/timeouts/suite-level.js
    
      a suite of tests
        ✓ should take less than 500ms (306ms)
        ✓ should take less than 500ms as well (251ms)
    
      2 passing (564ms)
    

    如果把时间从this.timeout(500)改成this.timeout(300),,就会的到超时错误

    ➜  learn-mocha git:(master) ✗ mocha test/timeouts/suite-level.js
    
      a suite of tests
        1) should take less than 300ms
        ✓ should take less than300ms as well (253ms)
    
      1 passing (569ms)
      1 failing
    
      1) a suite of tests
           should take less than 300ms:
         Error: Timeout of 300ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves. (/blog/learn-mocha/test/timeouts/suite-level.js)
    

    用例级别

    在测试级别it()中使用方法也差不多。在it()中使用this.timeout(0)可以重载/消除测试套件定义的超时时间。

    it('should take less than 500ms', function(done){
      this.timeout(500);
      setTimeout(done, 300);
    });
    
    ➜  learn-mocha git:(master) ✗ mocha test/timeouts/test-level.js
    
      ✓ should take less than 500ms (302ms)
    
      1 passing (308ms)
    

    钩子级别(HOOK-LEVEL)

    在钩子级别HOOK-LEVEL中使用方法也差不多。使用this.timeout(0)也可以s禁用hook的超时。

    describe('a suite of tests', function() {
      beforeEach(function(done) {
        this.timeout(3000); // A very long environment setup.
        setTimeout(done, 2500);
      });
    
      it('it', function(done) {
        setTimeout(done, 20);
      })
    });
    
    ➜  learn-mocha git:(master) ✗ mocha test/timeouts/hook-level.js
    
      a suite of tests
        ✓ it
    
      1 passing (3s)
    

    DIFFS

    mocha支持来自断言库的有err.expected 和 err.actual 实际属性的任何AssertionErrors错误 。mocha将自动显示预期和实际之间的差异。下面是一个“字符串”差异的例子:

    const assert = require('assert')
    
    describe('suite 1', function () {
      it('test case 1', function () {
        assert.equal(-1, [1, 2, 3].indexOf(4))
      })
    
      it('test case 2', function () {
        assert.equal('test', [1, 2, 3].toString())
      })
    })
    
    ➜  learn-mocha git:(master) ✗ mocha test/diffs.js
    
      suite 1
        ✓ test case 1
        1) test case 2
    
      1 passing (9ms)
      1 failing
    
      1) suite 1
           test case 2:
    
          AssertionError [ERR_ASSERTION]: 'test' == '1,2,3'
          + expected - actual
    
          -test
          +1,2,3
    
          at Context.<anonymous> (test/diffs.js:9:12)
    

    使用命令(USAGE)

    ➜  learn-mocha git:(master) ✗ mocha --help
    
      Usage: mocha [debug] [options] [files]
    
      Options:
    
        -V, --version                           output the version number
        -A, --async-only                        force all tests to take a callback (async) or return a promise
        -c, --colors                            force enabling of colors
        -C, --no-colors                         force disabling of 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 (default: spec)
        -S, --sort                              sort test files
        -b, --bail                              bail after first test failure
        -d, --debug                             enable node's debugger, synonym for node --debug
        -g, --grep <pattern>                    only run tests matching <pattern>
        -f, --fgrep <string>                    only run tests containing <string>
        -gc, --expose-gc                        expose gc extension
        -i, --invert                            inverts --grep and --fgrep matches
        -r, --require <name>                    require the given module
        -s, --slow <ms>                         "slow" test threshold in milliseconds [75]
        -t, --timeout <ms>                      set test-case timeout in milliseconds [2000]
        -u, --ui <name>                         specify user-interface (bdd|tdd|qunit|exports) (default: bdd)
        -w, --watch                             watch files for changes
        --check-leaks                           check for global variable leaks
        --full-trace                            display the full stack trace
        --compilers <ext>:<module>,...          use the given module(s) to compile files (default: )
        --debug-brk                             enable node's debugger breaking on the first line
        --globals <names>                       allow the given comma-delimited global [names] (default: )
        --es_staging                            enable all staged features
        --harmony<_classes,_generators,...>     all node --harmony* flags are available
        --preserve-symlinks                     Instructs the module loader to preserve symbolic links whenresolving and caching modules
        --icu-data-dir                          include ICU data
        --inline-diffs                          display actual/expected differences inline within each string
        --no-diff                               do not show a diff on failure
        --inspect                               activate devtools in chrome
        --inspect-brk                           activate devtools in chrome and break on the first line
        --interfaces                            display available interfaces
        --no-deprecation                        silence deprecation warnings
        --exit                                  force shutdown of the event loop after test run: mocha willcall process.exit
        --no-timeouts                           disables timeouts, given implicitly with --debug
        --no-warnings                           silence all node process warnings
        --opts <path>                           specify opts path (default: test/mocha.opts)
        --perf-basic-prof                       enable perf linux profiler (basic support)
        --napi-modules                          enable experimental NAPI modules
        --prof                                  log statistical profiling information
        --log-timer-events                      Time events including external callbacks
        --recursive                             include sub directories
        --reporters                             display available reporters
        --retries <times>                       set numbers of time to retry a failed test case
        --throw-deprecation                     throw an exception anytime a deprecated function is used
        --trace                                 trace function calls
        --trace-deprecation                     show stack traces on deprecations
        --trace-warnings                        show stack traces on node process warnings
        --use_strict                            enforce strict mode
        --watch-extensions <ext>,...            additional extensions to monitor with --watch (default: js)
        --delay                                 wait for async suite definition
        --allow-uncaught                        enable uncaught errors to propagate
        --forbid-only                           causes test marked with only to fail the suite
        --forbid-pending                        causes pending tests and test marked with skip to fail the suite
        --file <file>                           include a file to be ran during the suite (default: )
        --exclude <file>                        a file or glob pattern to ignore (default: )
        -h, --help                              output usage information
    
      Commands:
    
        init <path>                             initialize a client-side mocha setup at <path>
    

    解释几个常用的选项

    • -V, --version 版本号
    • -b, --bail 只对第一个抛出异常处理
    • -d, --debug 开启node的debug模式,对标记了debugger语句的代码进行调试
    • -t, --timeout <ms>指定测试用例的超时时间。默认是2000毫秒。
    • -w, --watch 用来监测测试文件的变化
    • -s, --slow <ms> 指定测试用例执行时间为慢的阈值。默认是75毫秒。

    接口(INTERFACES)

    mocha 的接口系统允许开发人员选择自己的DSL风格。mocha 拥有 BDDTDDExportsQUnit 和 Require风格的接口。

    BDD

    BDD 接口 提供 describe()context()it()specify()before()after()beforeEach()afterEach()。 describe() = context()it() = specify() 前面的例子都是用的 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

    类似于 mocha 前身 expresso。关键字 beforeafterbeforeEachafterEach 是special-cased。 测试套件是对象,函数是测试用例。

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

    QUNIT

    类似QUnit。测试套件单独定义在测试用例之前,像TDD一样支持suite()和test(),像BDD一样支持hooks。同样包括before()after()beforeEach()afterEach()

    unction 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()来导入describe()it()的方法。可以自己定义别名。注意:只能用mocha命令执行,node不行。

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

    报告(REPORTERS)

    Mocha提供了多种console端报告模式

    • mocha --reporter spec 这是默认模式。是一个按照测试套件和用例分层次的视图
    • mocha --reporter dot 显示一个由点组成的矩阵。点的颜色代表着不同的测试结果
    • mocha --reporter nyan 显示了一个图。。。。。
    • mocha --reporter tap 基于Test Anything Protocol (TAP)
    • mocha --reporter landing 模拟飞机降落
    • mocha --reporter list 以列表的形式显示每一个测试用例
    • mocha --reporter progress 以进度条的形式显示
    • mocha --reporter json 输出json格式的报告
    • mocha --reporter min 只输出summary。可以与mocha -w一起使用
    • mocha --reporter doc 输出HTML格式的报告
    • mocha --reporter markdown 输出HTML格式的报告





    参照链接:

  • 相关阅读:
    题解 CF1156A 【Inscribed Figures】
    P1352 没有上司的舞会 题解
    厦门大学附属实验中学第五次OI模拟赛(XDFZOI5)比赛须知
    属于自己的期中考总结
    做题笔记 【模板】字符串哈希
    2018 总结
    做题笔记 图的遍历 P3916
    做题笔记 Splitting into digits CF1104A
    LIS (nlogn)
    标准正交基
  • 原文地址:https://www.cnblogs.com/lilicat/p/10438214.html
Copyright © 2011-2022 走看看