Mocha 下测试异步代码

JavaScript NPM Promise 回调函数 Chai Mocha 测试 BDD 异步

利用 Mocha 进行 BDD 风格测试中介绍了Mocha测试框架和 Chai断言库的使用。JavaScript天生就是异步的, 这意味着在JavaScript测试中往往会需要异步断言。 本文介绍如何使用Chaichai-as-promised来测试Promise。

Mocha测试异步代码

Mocha本身是支持异步测试的。只需要为describe回调函数添加一个done参数, 成功时调用done(),失败时调用done(err)。例如:

var expect = require('chai').expect;
describe('db', function() {
    it('#get', function(done) {
        db.get('foo', function(err, foo){
            if(err) done(err);        
            expect(foo).to.equal('bar');
            done();
        });
    });
});
  • 如果未调用done函数,Mocha会一直等待直到超时。
  • 如果未添加done参数,Mocha会直接返回成功,不会捕获到异步的断言失败。例如:
it('#get', function(){
    setTimeout(function(){
        expect(1).to.equal(2);
    }, 100);
});

运行上述测试Mocha总会提示Passing。

Mocha怎么知道是否要等待异步断言呢?因为JavaScript中的Function有一个length属性, 通过它可以获得该函数的形参个数。Mocha通过传入回调的length来判断是否需要等待。

Mocha测试Promise

测试Promise有两种方式:可以采用上述done的方式,也可以直接返回该Promise。 注意Promise也属于异步代码,如果未采用上述方式,Mocha将无法捕捉到异步的断言失败。

done回调的方式

describe('#find()', function() {
    it('respond with matching records', function(done) {
        db.find({ name: 'harttle' })
            .then(function(user){
                expect(user.name).to.equal('harttle');
                done();
            })
            .catch(err => done(err));
    });
});

直接返回Promise的方式

describe('#find()', function() {
    it('respond with matching records', function() {
        return db.find({ name: 'harttle' }).then(function(user){
            expect(user.name).to.equal('harttle');
        });
    });
});

expect失败或db.find失败都会导致Promise失败(Rejected), 这时Mocha判定测试失败,否则判定测试成功。

注意两种方式不可同时使用,即返回了Promise就不要调用done,否则Mocha会报错。

Chai As Promised

chai-as-promised是Chai的一个断言库插件, 该插件可以大大简化Promise相关的断言。 它为Promise提供了.should.eventrually属性, 通过该属性可以使用任何Chai提供的BDD断言方法。

先使用NPM安装chai-as-promised

npm install --save-dev chai-as-promised

现在我们用chai as promised重写上述测试逻辑:

var chai = require('chai');
chai.use(require("chai-as-promised"));

describe('#find()', function() {
    it('respond with matching records', function() {
        return expect(db.find({ name: 'harttle' }))
            .to.eventually.have.property('name', 'harttle');
    });
    it('should be fulfilled', function(){
        return expect(db.remove('user')).to.eventually.be.fulfilled;
    });
});

参考阅读

Harttle

致力于简单的、一致的、高效的前端开发

看看这个?