Unit Test
Vona strongly recommends test-driven development. Test-driven development can effectively accumulate development results and identify potential problems as soon as possible when code changes occur, thereby significantly improving the robustness of the code
Vona uses a parallel mechanism to run test files, thereby significantly improving test efficiency
WARNING
Sqlite3 only supports one write connection, so parallel mechanism is not supported
Create test file
1. Cli command
$ vona :create:test student --module=demo-student2. Menu command
TIP
Context menu - [Module Path]: Vona Create/Test
Execute unit tests
$ npm run testWhen this command is executed, the system will perform the following steps:
- Create a global
appobject - Clean up
Redisdata - Delete the old database and recreate a new database
- Execute migration code
Parallelexecute unit test files
$ npm run db:resetUnlike the test command, db:reset only executes the first four steps and does not execute the unit test files
Test coverage
$ npm run covExample
1. Simulate the request context object
describe('student.test.ts', () => {
it('action:student', async () => {
await app.bean.executor.mockCtx(async () => {
// do something
});
});
});- Specify the current language for ctx
describe('student.test.ts', () => {
it('action:student', async () => {
await app.bean.executor.mockCtx(async () => {
// do something
}, { locale: 'zh-cn' });
});
});2. Get the module Scope object
await app.bean.executor.mockCtx(async () => {
const scopeStudent = app.scope('demo-student');
});3. Use Service
const scopeStudent = app.scope('demo-student');
const students = await scopeStudent.service.student.findMany();4. Use Model
const scopeStudent = app.scope('demo-student');
const students = await scopeStudent.model.student.select();5. Using Entity
const scopeStudent = app.scope('demo-student');
const tableName = scopeStudent.entity.student.$table;
const fieldName = scopeStudent.entity.student.name;6. Access API to test Controller
await app.bean.executor.mockCtx(async () => {
const students = await app.bean.executor.performAction('get', '/demo/student');
});7. Simulate authentication
- Simulate login
await app.bean.executor.mockCtx(async () => {
await app.bean.passport.signinMock();
});You can specify the login username, the default is admin
await app.bean.passport.signinMock('admin');- Get current user information
await app.bean.passport.signinMock();
const passport = app.ctx.passport;
const user = app.ctx.user;
const passport = app.bean.passport.current;
const user = app.bean.passport.currentUser;
const auth = app.bean.passport.currentAuth;
const roles = app.bean.passport.currentRoles;- Simulate logout
await app.bean.passport.signout();8. Tools: assert
Vona uses Node's built-in assertion library
import assert from 'node:assert';
await app.bean.executor.mockCtx(async () => {
assert.equal(app.config.server.listen.port, 7102);
});9. Tool: catchError
catchError can capture error exception more elegantly
- General writing
await app.bean.executor.mockCtx(async () => {
const scopeStudent = app.scope('demo-student');
try {
const students = await scopeStudent.service.student.findMany();
} catch (err) {
// do something
}
});- Use catchError
import { catchError } from '@cabloy/utils';
await app.bean.executor.mockCtx(async () => {
const scopeStudent = app.scope('demo-student');
const [students, err] = await catchError(() => {
return scopeStudent.service.student.findMany();
});
if (err) {
// do somthing on err
}
});10. Complete Crud test
describe('student.test.ts', () => {
it('action:student', async () => {
await app.bean.executor.mockCtx(async () => {
// data
const data: DtoStudentCreate = {
name: '__Tom__',
description: 'This is a test',
};
const dataUpdate: DtoStudentUpdate = {
name: '__TomNew__',
description: 'This is a test',
};
// login
await app.bean.passport.signinMock();
// create
const studentId = await app.bean.executor.performAction('post', '/demo/student', { body: data });
assert.equal(!!studentId, true);
// findMany
const queryRes: DtoStudentQueryRes = await app.bean.executor.performAction('get', '/demo/student');
assert.equal(queryRes.list.findIndex(item => item.name === data.name) > -1, true);
// update
await app.bean.executor.performAction('patch', '/demo/student/:id', {
params: { id: studentId },
body: dataUpdate,
});
// findOne
let student: EntityStudent = await app.bean.executor.performAction('get', '/demo/student/:id', { params: { id: studentId } });
assert.equal(student.name, dataUpdate.name);
// delete
await app.bean.executor.performAction('delete', '/demo/student/:id', { params: { id: student.id } });
// findOne
student = await app.bean.executor.performAction('get', '/demo/student/:id', { params: { id: student.id } });
assert.equal(student, undefined);
// logout
await app.bean.passport.signout();
});
});
});