测试,很多人都不陌生。出名的测试框架有很多,jasmine,karma,mocha 等。无论使用哪一种框架,功能都是一样的。这里我介绍一下 mocha,因为它支持定向测试(运行特定测试样例)和同步/异步测试,同时具有一些便于使用的测试 hook。
npm install mocha chai supertest
- chai
chai 提供了一套语义化的断言机制,你可以使用
expect(sth).to.be(sth)
,sth.should.not.be(sth)
或者assert.equal(sth, sth)
三种语义化风格的断言机制。 - mocha
mocha 使用如下框架来测试:
每一个 describe 是一个测试模块,里面定义的 it 是测试模块中的小模块,也就是具体的测试样例。
describe('Test module', function() { it('sub module 1', function() { // assert }); it('sub module 2', function() { // assert }); });
- supertest supertest 是辅助 mocha 进行 HTTP 请求的测试库,它包装了模拟 HTTP 请求的函数,使得网络测试变得十分简单。
我们新建一个工程,目录如下:
├─test
│ ├─sync_test.js
│ ├─async_test.js
│ └─http_test.js
├─package.json
├─sum.js
└─app.js
测试代码均放置在 test 目录下
我们利用 chai 提供的断言于 mocha 的测试框架来实现同步测试。
下面我们来看看同步函数是如何测试的:
// sync_sum.js
module.export = function(a, b) {
return a + b;
}
// sync_test.js
const chai = require('chai');
const sum = require('../sum');
describe('Test sync function', () => {
it('Sum 2 and 3', () => {
chai.expect(sum(2, 3)).to.be(5);
});
it('Sum 3 and 3', () => {
chai.expect(sum(3, 3)).to.be(6);
});
});
JavaScript 最令人喜欢,也最令人痛恨的异步机制,而 mocha 对于异步函数有着十分优秀的支持机制。你可以选择两种方式来完成异步测试:
- 利用
done
回调函数 在异步函数中,我们显示的调用一个done
函数,就可以通知 mocha 这个异步函数的完成情况。这样就不用一直等待异步函数执行情况。 - 直接使用
promise
mocha 支持直接返回一个 promise,通过 promise 的 resolve 还是 reject 来判断这个测试是否通过。
在mocha 6.0.0以后,返回 promise 时,再调用 done 是非法行为,该测试不会通过。但在这个版本以前,mocha 会自动略过 promise 中的 done 函数。
// async_test.js
const chai = require('chai');
const fs = require('fs');
let read = function (filename) {
let promise = new Promise(function(resolve, reject) {
fs.readFile(filename, 'utf8', function(err, data) {
if (err){
reject(err);
}
resolve(data);
});
});
return promise;
}
describe('Test async func', () => {
it('Async with done', function(done) {
let x = true;
let f = function() {
x = false;
chai.expect(x).to.be.not.ok;
done(); // inform mocha test done
};
setTimeout(f, 4000);
});
it('Async with promise', async () => {
// return read('sum.js') is supported for promise
// but here I'd like to change it into
// sync way which could be more controlled
let data = await read('sum.js');
chai.expect(data).to.not.be.a('null');
});
});
HTTP 测试借助 supertest 会变得十分方便。我们只需要将运行的 koa server 作为参数传递给 supertest,它就会知道请求发送的地址。然后我们可以通过 supertest 模拟请求,并且判断请求的结果是否符合预期。因为 HTTP 请求是异步的,所以 supertest 还是需要调用 done 的。
// app.js
const koa = require('koa');
const body = require('koa-body');
const router = require('router')();
const app = new koa();
// request data parser
app.use(koaBody());
// routers
router.get('/api/get-server-state', (ctx, next) => {
ctx.response.body = {
msg: 'Server is ok.'
};
});
router.post('/api/sum-a-b', (ctx, next) => {
let a = ctx.request.body.a;
let b = ctx.request.body.b;
ctx.response.body = {
res: a + b
};
});
app.use(router.routes());
module.exports = app;
app.listen(3000, () => {
console.log('Koa running at port 3000...');
});
// http_test.js
const app = require('../app');
const request = supertest(app.listen());
describe('Test HTTP request', () => {
it('[GET] /api/get-server-state', (done) => {
request.get('/get-server-state')
.send()
.expect(200, { msg: 'Server is ok.' }, done);
});
it('[POST] /api/add-a-b', (done) => {
request.post('/api/sum-a-b')
.set('Content-Type', 'application/json')
.send({ a: 2, b: 3 })
.expect(200, { res: 5 }, done);
});
});
输入 .\node_modules\.bin\mocha
,mocha 会自动运行 test 目录下所有的测试文件。当然,你可以在 package.json
中加入 test script:
"scripts": {
"test": "./node_modules/.bin/mocha",
}
这样就可以直接通过 npm test
直接进行测试。
我们前面的测试代码结果如下:
一开始说过,mocha 可以指定运行测试样例,如果我们使用 npm test
,怎么办呢?很简单,我们可以在 test 目录下,添加一个 mocha.opts
文件,这里面写下你希望运行 mocha 的时候添加的参数,比如异步函数的等待执行时间等。
下面的文件就指定了只运行 test_program.js 测试文件,并且指定了测试报告主题。更多参数设置可以前往 mocha 的官网进行查看
test/test_program.js
--reporter landing