官方推薦測(cè)試框架:Mocha(Mocha中文網(wǎng))
官方推薦斷言庫(kù):power-assert
Egg.js 中已經(jīng)內(nèi)置 Mocha、co-mocha、power-assert,nyc 等模塊,只需要在 package.json 上配置好 scripts.test 即可。
{
"scripts": {
"test": "egg-bin test"
}
}
運(yùn)行測(cè)試:
npm test
注意:
npm test會(huì)首先進(jìn)行 eslint 檢查,若有error則不會(huì)開(kāi)始測(cè)試。
指定文件路徑,可以對(duì)某一個(gè)單元測(cè)試文件進(jìn)行測(cè)試:
npm test ./path/to/user.test.js
目錄結(jié)構(gòu)
約定 test 目錄為存放所有測(cè)試腳本的目錄。
測(cè)試腳本文件統(tǒng)一按 ${filename}.test.js 命名,必須以 .test.js 作為文件后綴。
test
├── controller
│ └── home.test.js
├── hello.test.js
└── service
└── user.test.js
Controller 測(cè)試
describe 和 it 的第一個(gè)字段都只是描述,每一個(gè) it 是一個(gè)測(cè)試用例。
'use strict';
const { app, assert } = require('egg-mock/bootstrap');
describe('test/app/controller/home.test.js', () => {
it('should assert', () => {
const pkg = require('../../../package.json');
assert(app.config.keys.startsWith(pkg.name));
// const ctx = app.mockContext({});
// yield ctx.service.xx();
});
it('should GET /', () => {
return app.httpRequest()
.get('/') // GET 請(qǐng)求
.expect(200) // 期望返回的 status 200
.expect('hi, egg'); // 期望返回的 body,支持 string/
});
});
describe('test/app/controller/user.test.js', () => {
it('should POST /users', () => {
return app.httpRequest()
.post('/users') // POST 請(qǐng)求
.send({ username: 'Mike', password: '123456' }) // post body
.expect(200)
.then(response => {
// response.text 是返回的 body 字符串,轉(zhuǎn)成 json 后再通過(guò) assert 校驗(yàn)
const res = JSON.parse(response.text);
assert.equal(res.code, '0000'); // 業(yè)務(wù)錯(cuò)誤碼應(yīng)該為'0000',字符串對(duì)比
assert(res.data.userId); // userId應(yīng)該存在,注意 0、false、空字符串 都會(huì)被判定為失敗,與 assert.ok() 等效
});
});
});
前置和后置步驟
Mocha 使用 before/after/beforeEach/afterEach 來(lái)處理前置后置任務(wù),基本能處理所有問(wèn)題。 每個(gè)用例會(huì)按 before -> beforeEach -> it -> afterEach -> after 的順序執(zhí)行,而且可以定義多個(gè)。
describe('egg test', () => {
// Mocha 剛開(kāi)始運(yùn)行的時(shí)候會(huì)載入所有用例,這時(shí)調(diào)用 describe 方法,執(zhí)行 before()
before(() => console.log('order 1')); // 在當(dāng)前 describe 中的所有用例之前執(zhí)行
before(() => console.log('order 2')); // 支持多個(gè) before 函數(shù)
after(() => console.log('order 6')); // 在當(dāng)前 describe 中的所有用例之后執(zhí)行
beforeEach(() => console.log('order 3')); // 在當(dāng)前 describe 中的每個(gè)用例之前執(zhí)行
afterEach(() => console.log('order 5')); // 在當(dāng)前 describe 中的每個(gè)用例之后執(zhí)行
it('should worker', () => console.log('order 4'));
});
Service 測(cè)試
也可以直接對(duì) Service 層進(jìn)行測(cè)試。
describe('get()', () => {
it('should get exists user', async () => {
// 創(chuàng)建 ctx
const ctx = app.mockContext();
// 通過(guò) ctx 訪問(wèn)到 service.user,直接調(diào)用 user 的方法
const user = await ctx.service.user.get('admin');
assert(user);
assert(user.name === '管理員');
});
it('should get null when user not exists', async () => {
const ctx = app.mockContext();
const user = await ctx.service.user.get('admin');
assert(!user);
});
});