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