测试驱动
强烈建议基于测试驱动
开发。测试驱动
开发,可以有效沉淀开发成果,当代码出现变更时也能尽快锁定潜在问题,从而显著提升代码的鲁棒性
EggBorn在EggJS
的基础上,提供了一个便捷的框架,可以很方便的实现基于测试驱动
的开发
下面是模块test-todo
的测试驱动
的示范。可以此为范例,不断扩充测试用例
,尽可能多的提高代码覆盖率
- 用户登录
- 新建todo
- 提交todo(从
草稿状态
提交到正常状态
) - 查询todo
- 删除todo
测试用例
src/module/test-todo/backend/test/controller/test.test.js
const { app, mockUrl, mockInfo, assert } = require('egg-born-mock')(__dirname);
describe('[your tests start from here]', () => {
it('[atom]', async () => {
app.mockSession({});
// atomClass info
const atomClassModule = mockInfo().relativeName;
const atomClassName = 'todo';
// login as root
await app.httpRequest().post(mockUrl('/a/authsimple/passport/a-authsimple/authsimple')).send({
auth: 'root',
password: '123456',
});
// create
let result = await app.httpRequest().post(mockUrl('/a/base/atom/create')).send({
atomClass: { module: atomClassModule, atomClassName, atomClassIdParent: 0 },
});
assert(result.body.code === 0);
const atomKey = result.body.data;
// submit
result = await app.httpRequest().post(mockUrl('/a/base/atom/submit')).send({
key: atomKey,
item: {
atomName: 'test',
description: 'this is a test',
},
});
assert(result.body.code === 0);
// read
result = await app.httpRequest().post(mockUrl('/a/base/atom/read')).send({
key: atomKey,
});
assert(result.body.code === 0);
// delete
result = await app.httpRequest().post(mockUrl('/a/base/atom/delete')).send({
key: atomKey,
});
assert(result.body.code === 0);
});
});
名称 | 说明 |
---|---|
mockUrl | 用于构造完整的后端API接口地址 |
mockInfo | 用于获取当前测试所属模块的基本信息。比如当前模块名是test-todo ,但为了提升代码的灵活性,可以通过mockInfo().relativeName 获取 |
app.mockSession | 用于模拟Session环境 |
执行测试
$ npm run test:backend
测试覆盖率统计
$ npm run cov:backend
后端API路由version/test
在测试用例
执行之前,每个模块的后端API路由version/test
都会自动执行
可以在这个阶段准备一些测试数据(如测试用的角色
、用户
、权限
等等)
以模块test-todo
为例,添加如下测试数据:
- 添加用户
demo001
- 添加用户的登录认证信息
- 把用户
demo001
添加到角色registered
test-todo/backend/src/service/version.js
async test() {
// create test users: demo001
const users = [
{ userName: 'demo001', roleName: 'registered' },
];
const userIds = [];
for (const user of users) {
// add user
userIds[user.userName] = await this.ctx.meta.user.add({
userName: user.userName,
realName: user.userName,
});
// add auth info for login
await this.ctx.performAction({
method: 'post',
url: '/a/authsimple/auth/add',
body: {
userId: userIds[user.userName],
password: '123456',
},
});
// role
const role = await this.ctx.meta.role.get({ roleName: user.roleName });
// add user role
await this.ctx.meta.role.addUserRole({
userId: userIds[user.userName],
roleId: role.id,
});
}
}
app.meta.isTest, app.meta.isLocal
可以通过app.meta.isTest
、app.meta.isLocal
,在合适的环境加载合适的代码逻辑
比如,模块test-cook
里面的资源,只允许在测试环境
和开发环境
中生效,在生产环境
无效,可以操作如下:
test-cook/backend/src/models.js
const cook = require('./model/cook.js');
const cookType = require('./model/cookType.js');
const cookPublic = require('./model/cookPublic.js');
module.exports = app => {
const models = {
};
if (app.meta.isTest || app.meta.isLocal) {
Object.assign(models, {
cook,
cookType,
cookPublic,
});
}
return models;
};
模块test-cook
模块test-cook
是开箱即用的测试模块,提供大量的测试驱动
开发指引
评论: