2016-07-04 00:00:00

使用mocha对用Babel编译的代码进行单元测试

前言

async/await是node.js回调地狱的终极解决办法,谁用谁知道.
目前基本都采用Babel编译的形式将包含async/await的代码编译为ES5可执行代码,但是在单元测试中,如果直接使用mocha进行测试,由于测试文件没有被Babel编译,连词法分析也无法通过

引入Babel

以express为例,

npm install --save babel-core
npm install --save babel-preset-stage-3
npm install --save babel-preset-es2015
npm install --save-dev babel-plugin-transform-runtime
npm install --save babel-runtime

在项目根目录中新建.babelrc文件,输入如下内容:

{
    "presets":[
        "es2015",
        "stage-3"
    ],
    "plugins": [
        ["transform-runtime", {
            "polyfill": false,
            "regenerator": true
        }]
    ]
}

app.js的加载bodyParser的语句后面添加

require("babel-core/register");

即可通过require的钩子来对之后加载的模块进行自动编译

使用Babel编译测试文件

使用如下语句为mocha进行编译

mocha --compilers js:babel-core/register

将上面的语句写入package.json中的scripts里的test

与引入Babel一样,如上语句调用了babel-core/register为转码器,请确保其存在

此处的转码器同样依赖.babelrc,请再次确认内容是否正确

单元测试

以Think.js(MVC,类似与ThinkPHP)为例,使用如上的配置进行ES6的测试.

首先创建test/index.js文件,这里调用calculate这个service,测试其中的getResult函数,书写如下内容:

"use strict";

var assert = require("assert");
var path = require("path");
var xlsx = require("xlsx");

var thinkjs = require("thinkjs");
thinkjs.load();

var calculate = think.safeRequire(path.resolve(__dirname, "../src/common/service/calculate.js"));

describe("unit test", function(){
    const workbook = xlsx.readFile("/opensource/telecomCharges/testCase.xlsx");
    const sheetNames = workbook.SheetNames;
    const worksheet = workbook.Sheets[sheetNames[0]];

    var json = xlsx.utils.sheet_to_json(worksheet);
    var length = json.length;

    var outputArr = [];

        it("use case "+index, function(done){

                let inputData = {
                    minutes : parseFloat(item["通话分钟"]),
                    times : parseInt(item["累积未交费次数"]),
                    isCrossYear : "on",
                    crossYearPrice: parseFloat(item["跨年未交费金额"]),
                };

                let  instance = new calculate();

                let date = instance.getResult(inputData);

                outputArr[index]={
                    "通话分钟":inputData.minutes,
                    "累积未交费次数":inputData.times,
                    "跨年未交费金额":inputData.crossYearPrice,
                    "预期输出":item["预期输出"],
                    "实际输出":date,
                    "是否成功":"失败",
                };

                assert.equal(date.toString(), item["预期输出"]); 

                outputArr[index]["是否成功"] = "成功";
                done();


        })

});

上面读取了一个表格文件里的测试用例,并进行自动化单元测试.其中每个it的测试函数都传入了一个done参数,这个参数是在异步嵌套最底层中被调用,用来提醒mocha这个测试已经完成了.这里的单元测试没有异步操作,因此可以将done省略

注意,如果使用了其他框架,请在测试开始时对框架进行初始化.因为使用ES6来继承的话,几乎所有框架都默认会继承运行环境中的某个全局变量,不初始化会导致编译无法通过.以thinkJS为例,使用require("thinkjs").load()来初始化框架环境

var thinkjs = require("thinkjs");
thinkjs.load();

同时,使用如下语句进行require

var calculate = think.safeRequire(path.resolve(__dirname, "../src/common/service/calculate.js"));

think.safeRequire只是thinkjs对require的一个封装,当对应文件不存在时返回null

好了,现在可以npm test了,如下,使用边界值,等价类,决策表三种用例设计方法设计出来的102个测试用例全部通过

如果babel-preset-${name}不存在的话,使用npm install --save-dev babel-preset-${name}进行安装即可

其他

既然使用了读取表格来进行测试,那么不用表格将输出结果打印出来就十分可惜了.
与很多产品类似,mocha提供一大堆钩子函数,其中describe的钩子函数after(function(){})能够进行当前describe中所有用例执行完毕后最后要执行的操作.由于node.js异步的特性,mocha的所有用例的测试也会被压入事件循环中的线程池,因此必须使用after这种钩子函数


    after(function() {

            var length = json.length;

            console.log("writing file")

            var _headers = ["用例编号","通话分钟", "累积未交费次数", "跨年未交费金额", "预期输出","实际输出","是否成功"];
            var _data = outputArr;

            var headers = _headers
                            .map((v, i) => Object.assign({}, {v: v, position: String.fromCharCode(65+i) + 1 }))
                            .reduce((prev, next) => Object.assign({}, prev, {[next.position]: {v: next.v}}), {});

            var data = _data
                        .map((v, i) => _headers.map((k, j) => Object.assign({}, { v: v[k], position: String.fromCharCode(65+j) + (i+2) })))
                        .reduce((prev, next) => prev.concat(next))
                        .reduce((prev, next) => Object.assign({}, prev, {[next.position]: {v: next.v}}), {});

            var output = Object.assign({}, headers, data);

            var ref = "A1" + ":" + "G"+length;

            var wb = {
                SheetNames: ["mySheet"],
                Sheets: {
                    "mySheet": Object.assign({}, output, { "!ref": ref })
                }
            };

            xlsx.writeFile(wb, "/opensource/telecomCharges/output.xlsx");
    });

如上就是输出结果数组为表格的代码了.我觉得这里输出部分有些累赘,但是去查询xlsx这个模块的文档时,并没有找到更加简洁的被抽象为util的内部方法

如下图,这就是输出的表格了,用来演示自动化测试十分方便

本文链接:https://smallpath.me/post/使用mocha测试ES6代码

-- EOF --