单元测试框架Mocha Chai的使用

前言(个人见解)

随着前端工作量、代码量增多,如何保证代码质量,在angular、react、vue等多种mvvm框架的环境下,框架有自己的语法规则,即使每个人有每个人不同的编码风格,但用框架写出的代码都大同小异,代码质量上差距不太大,但在写一些类库,组件的时候必须要谨慎,因为组件类库的,会有同事,或者作为开源,给大家使用的,尽量避免bug的出现,这个时候需要代码健壮,需要产出高质量的代码,就必须要提升测试的力度,这个时候单元测试就派上用场了。



单元测试的原理

经常与单元测试联系起来的另外一些开发活动包括代码走读(Code review),静态分析(Static analysis)和动态分析(Dynamic analysis)。静态分析就是对软件的源代码进行研读,查找错误或收集一些度量数据,并不需要对代码进行编译和执行。动态分析就是通过观察软件运行时的动作,来提供执行跟踪,时间分析,以及测试覆盖度方面的信息。



使用技术

  • Mocha:Javascript单元测试框架
  • Chai:断言库,配合Mocha一起使用


下面案例所用mocha Api 总结

  • 使用mocha测试异步代码,只需要在测试完成的时候调用一下回调函数即可。通过添加一个回调函数(通常命名为done)给it()方法,Mocha就会知道,它应该等这个函数被调用的时候才能完成测试。
describe('User', function() {
    describe('#save()', function() {
        it('should save without error', function() {
            var user = new User('Luna')
            user.save(function(err) {
                if(err) done(err);
                else done()
            })
        })
    })
})
复制代码
  • 同时,除了使用done()回调函数,你也可以返回一个Promise。这种方式对于测试那些返回promies的方法是实用的。
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);
  });
});
复制代码


下面案例所用chaiJS Api 总结

语言链

以下是作为可链接的getter提供,以提高断言的可读性。

  • to
  • be
  • been
  • is
  • that
  • which
  • and
  • has
  • have
  • with
  • at
  • of
  • same

.equal(val [,msg])

  • @param {Mixed} val
  • @param {String} msg optional
expect(1).to.equal(1);
expect('foo').to.equal('foo');
复制代码

在链中较早添加以使用深度相等。有关深度相等算法的信息,请参阅 项目页面:https://github.com/chaijs/deep-eql。.deepdeep-eql

// Target object deeply (but not strictly) equals `{a: 1}`
expect({a: 1}).to.deep.equal({a: 1});
expect({a: 1}).to.not.equal({a: 1});

// Target array deeply (but not strictly) equals `[1, 2]`
expect([1, 2]).to.deep.equal([1, 2]);
expect([1, 2]).to.not.equal([1, 2]);
复制代码


一个简单小实例

  1. 全局安装Mocha

npm install --global mocha

  1. 安装chai

npm install --save-dev chai

  1. 创建项目目录结构
|—— lib  // 功能js的文件夹  
|—— tests  // 测试用例js的文件夹 
|—— index.js  // 主要入口 
|—— package.json  // 依赖包信息
|—— README.md  // 项目说明
复制代码
  1. 编写主要入口文件index.js
var file = require('./lib/file.js');

export default {
    writeFile: file.writeFile,
    readFile: file.readFile
}
复制代码
  1. 编写公共方法js (lib/utils.js)
var Promise = require("es6-promise").Promise;
 
/**
 * 提供各种工具方法
 * @type {{*}}
 */
module.exports = {
    /**
     * 获取Defer对象
     * @return {[type]} [description]
     */
    getDefer: function (){
        var deferred = {};
        deferred.promise = new Promise(function(resolve, reject){
            deferred.resolve = resolve;
            deferred.reject = reject;
        });
        return deferred;
    },
    /**
     * promise when方法
     * @param promises promise数组
     * @returns {[type]} [description]
     */
    when: function(promises) {
        var deffered = this.getDefer();
        Promise.all(promises).then(function(data) {
            deffered.resolve(data);
        }, function(err) {
            deffered.reject(err);
        });
        return deffered.promise;
    }
}
复制代码
  1. 编写读写文件方法 (lib/file.js)
var fs = require('fs');
var path = require('path');
var utils = require('./utils.js');
 
module.exports = {
    /**
     * 写文件
     * @param file 文件路径
     * @param data 数据
     */
    writeFile: function(file, data) {
        var deferred = utils.getDefer();
        file = path.resolve(file);
 
        fs.writeFile(file, data, 'utf-8', function(err) {
            if(err){
                deferred.reject(err);
            }else {
                deferred.resolve(true);
            }
        });
        return deferred.promise;
    },
    /**
     * 读文件
     * @param file 文件路径
     */
    readFile: function(file) {
        var deferred = utils.getDefer();
        file = path.resolve(file);
 
        fs.readFile(file, 'utf-8', function(err, data) {
            if(err){
                deferred.reject(err);
            }else {
                deferred.resolve(data);
            }
        });
        return deferred.promise;
    }
};

复制代码
  1. 编写读写文件方法 (lib/file.js)
var fs = require('fs');
var path = require('path');
var utils = require('./utils.js');
 
module.exports = {
    /**
     * 写文件
     * @param file 文件路径
     * @param data 数据
     */
    writeFile: function(file, data) {
        var deferred = utils.getDefer();
        file = path.resolve(file);
 
        fs.writeFile(file, data, 'utf-8', function(err) {
            if(err){
                deferred.reject(err);
            }else {
                deferred.resolve(true);
            }
        });
        return deferred.promise;
    },
    /**
     * 读文件
     * @param file 文件路径
     */
    readFile: function(file) {
        var deferred = utils.getDefer();
        file = path.resolve(file);
 
        fs.readFile(file, 'utf-8', function(err, data) {
            if(err){
                deferred.reject(err);
            }else {
                deferred.resolve(data);
            }
        });
        return deferred.promise;
    }
};
复制代码
  1. 编写utils测试 (lib/utils.js)
var utils = require('../lib/utils.js');
var expect = require('chai').expect;
 
describe('utils:工具方法测试', function() {
    //defer对象测试
    describe('utils.getDefer', function() {
        var deferred = utils.getDefer();
 
        it('defer成功', function() {
            deferred.resolve(true);
            return deferred.promise.then(function(data) {
                expect(data).to.be.equal(true);
            });
        });
 
        it('defer失败', function() {
            deferred.reject(true);
            return deferred.promise.then(function() {}, function(data) {
                expect(data).to.be.equal(true);
            });
        });
    });
    //when测试
    describe('utils.when', function() {
        var deferred1 = utils.getDefer();
        var deferred2 = utils.getDefer();
        var deferred3 = utils.getDefer();
        var deferred4 = utils.getDefer();
 
        it('when成功', function() {
            deferred1.resolve(true);
            deferred2.resolve(true);
            return utils.when([deferred1.promise, deferred2.promise]).then(function(data) {
                expect(data).to.be.deep.equal([true, true]);
            });
        });
 
        it('when失败', function() {
            deferred3.resolve(true);
            deferred4.reject(false);
            return utils.when([deferred3.promise, deferred4.promise]).then(function() {},function(data) {
                expect(data).to.be.equal(false);
            });
        });
    });
});

复制代码
  1. 编写file测试 (lib/file.js)
var file = require('../lib/file.js');
var expect = require('chai').expect;
 
describe('file:功能测试', function() {
 
    //writeFile功能测试
    describe('file.writeFile', function() {
 
        it('写文件:成功', function() {
            var path = 'README.md';
            var data = '说明文档';
            return file.writeFile(path, data).then(function(flag) {
                expect(flag).to.be.equal(true);
            });
        });
 
        it('写文件:失败', function() {
            var path = 'write-test.txt';
            var data = '我是写入的数据';
            return file.writeFile(path, data).then(function(){}, function(err) {
                expect(true).to.be.equal(true);
            });
        });
    });
 
    //readFile功能测试
    describe('file.readFile功能测试', function() {
 
        it('读文件:成功', function() {
            var path = 'README.md';
            return file.readFile(path).then(function(data) {
                expect(data).to.be.equal('说明文档');
            });
        });
 
        it('读文件:失败', function() {
            var path = 'write-test.txt';
            return file.readFile(path).then(function(){}, function(err) {
                expect(true).to.be.equal(true);
            });
        });
    });
});

复制代码

转载于:https://juejin.im/post/5c81d4846fb9a049cb198b53

你可能感兴趣的:(测试,前端,javascript)