王治 2019-06-21
mocha 是一个node单元测试框架,类似于前端的jasmine,语法也相近
supertest 用来测试node接口的库
should nodejs断言库,可读性很高
npm install mocha should supertest --save-dev
项目根目录下新建test文件夹,movies.spec.js
package.json中
"scripts": { "start": "pm2 start ecosystem.config.js", "test": "mocha --watch" //监听 test文件下的所有文件 },
这里我们来测试一个添加一条电影的接口
method: POST api: /api/movies document: { "title": 'movie0', "thumb": "public/p1075586949.jpg", "actors": [ "河正宇", "金允石", "郑满植" ], "type": [ "动作", "犯罪" ], "instruct": 'instruct...', "time": "2010-12-22(韩国)", }
这里电影信息会保存到movies集合中,类型信息保存在types集合中
需要注意的是如果多条电影有相同的type,则同一个电影类型在collection中只存一次,但会inc count字段
大体代码
/routes/movies.js
const MoviesModel = require('../models/movies_model') const CONFIG = require('../config/config') function callback(err, docs, res, next) { if (err) { next(err) return } res.json({ code: CONFIG.ERR_OK, data: docs }) } router.post('/', function (req, res, next) { MoviesModel.addMovies(req.body, (err, docs) => { callback(err, docs, res, next) }) });
/models/movies_model.js
const TypeModel = require('./type_model') class MoviesModel{ addMovies(data, callback) { const types = data.type DB.connect().then((db, err) => { TypeModel.addTypes(types, db) //保存分类 this.insertOne(db, data, callback) }).catch(e => { callback(e) }) } }
/models/type_model.js
class Type{ addTypes(typesArr, db) { const Types = db.collection('types') typesArr.forEach(item => { Types.update({ 'type_name': item }, { '$inc': { count: 1 } }, { upsert: true }) }) } }
测试中我们录入两条电影信息,两条的type字段中会有一个相同的类型
我们要验证的结论:
两条电影都成功录入,types集合中有三条document,"动作"的count是2,另两条count是1
当前环境是test时,使用测试数据库
/config/db.js let db_name='Movies' if(process.env.NODE_ENV=='test'){ db_name='Movies_test' } const url = f(`mongodb://%s:%s@localhost:3307/${db_name}?authMechanism=%s`, user, pwd, authMechanism)
测试数据
const movieInfo = { "title": 'movie0',"thumb": "public/p1075586949.jpg", "actors": [ "河正宇", ], "type": [ "动作", "犯罪" ], "instruct": 'instruct...',"time": "2010-12-22(韩国)", } const movieInfo1 = { "title": 'movie1',"thumb": "public/p1075586949.jpg", "actors": [ "河正宇", ], "type": [ "动作", "爱情" ], "instruct": 'instruct...',"time": "2010-12-22(韩国)", }
测试代码
process.env.NODE_ENV = 'test' //运行时,会将当前环境设置为test,连接数据库时使用Movies_test库,如上 const should = require('should') const request = require('supertest') const app = require('../app') describe('Movies Test',()=>{ describe('POST /movies',()=>{ //每个it语句运行开始之前会插入数据 beforeEach(function (done) { request(app) //启动node服务 .post('/api/movies').send(movieInfo).then(() => { return request(app).post('/api/movies').send(movieInfo1) }).then(res => { done() }) }) //每个it语句运行完之后会清除表数据 afterEach(function (done) { MoviesModel.remove(() => { TypeModel.remove(() => { done() }) }) }) //测试录入成功 it('add movie and get the added movie', function (done) { request(app) .get('/api/movies') .end((er, res) => { should(res.body.data).have.length(2) should(res.body.data[0]).have.property('title', 'movie1') done() }) }) //类型已经存在的就不在存了 it('repeat type not saved,will only increment count', function (done) { request(app) .get('/api/types') .then(res => { should(res.body.data).have.length(3) should(res.body.data[0]).have.property('count', 2) //"动作"的count是2 should(res.body.data[1]).have.property('count', 1) should(res.body.data[2]).have.property('count', 1) done() }) }) }) })
详细完整的对每个接口的测试见 test