在开发中,为项目生成文档是很常见的需求,很多第三方库(如 jsdoc 、 swagger 等)的做法是为需要生成文档的函数编写相应的符合规范的注释,然后运行相应的命令,生成一个静态网页形式的文档。
用注释生成文档的好处是可以为无论是普通函数还是 API,只要编写了相应的注释都能生成相应的文档,然而这种做法总觉得有点繁琐,尤其是只需要为 API 生成文档的时候,需要手动编写大量的输入和输出作为使用示例。而且我只想需要 markdown 形式的文档,丢在内部 Gitlab 的 wiki 上供前端人员査阅,然后可以根据 commit 的 history 查阅不同的版本。
不想手动为 API 文档编写大量的输入输出,那哪里会有输入输出呢,就很容易的想到了单元测试会产生输入和输出。好,那就用单元测试来为 API 生成文档。
我在单元测试中主要用的库有 mocha 、 supertest 和 power-assert ,Web 框架为 express 。
完整代码示例:
// app.js const express = require('express'); const bodyParser = require('body-parser'); const app = express(); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.post('/user/create', function(req, res){ const name = req.body.name; res.json({ status: 200, error_code: 0, message: 'success', data: { id: '123abc', name: 'node', gender: 'male', age: 23, }, }); }); app.get('/user/search', function(req, res){ const name = req.query.name; res.json({ status: 200, error_code: 0, message: 'success', data: { id: '123abc', name: 'node', gender: 'male', age: 23, }, }); }); app.get('/user/:id', function(req, res){ const userId = req.params.id; res.json({ status: 200, error_code: 0, message: 'success', data: { id: '123abc', name: 'node', gender: 'male', age: 23, }, }); }); app.listen(3000, function(){ console.log(`Server is listening on 3000`); }); module.exports = app; |
下面是测试文件。
// test/uset.test.js const assert = require('power-assert'); const supertest = require('supertest'); const U = require('../utils'); const app = require('../app'); const agent = supertest.agent(app); describe('Test', function(){ it('should create user success', function(done){ U.test({ agent, file: 'user', group: '用户相关API', title: '创建用户', method: 'post', url: '/user/create' params: { name: { value: 'node', type: 'String', required: true, desc: '名称' }, gender: { value: 'male', type: 'String', required: false, desc: '性别' }, age: { value: 23, type: 'Int', required: false, desc: '' }, }, headers: { entrance: 'client' }, expect: 200, callback (err, res) { if (err) return done(err); assert(res.body.data.name === 'node'); assert(res.body.data.age === 23); done(); }, }); }); it('should search user success', function(done){ U.test({ agent, file: 'user', group: '用户相关API', title: '搜索用户', method: 'get', url: '/user/search' params: { name: { value: 'node', type: 'String', required: true, desc: '名称' }, }, expect: 200, callback (err, res) { if (err) return done(err); assert(res.body.data.name === 'node'); assert(res.body.data.age === 23); done(); }, }); }); it('should search user success', function(done){ U.test({ agent, file: 'user', group: '用户相关API', title: '获取用户信息', method: 'get', url: '/user/:id' params: { id: { value: '123abc', type: 'String', required: true, desc: '' }, }, expect: 200, callback (err, res) { if (err) return done(err); assert(res.body.data.name === 'node'); assert(res.body.data.age === 23); done(); }, }); }); }); |