一步一步搭建react应用-node中使用 mocha + supertest + should 来写单元测试

[一步一步构建一个react应用-开篇](https://segmentfault.com/a/11...

git地址

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,next) {
    MoviesModel.addMovies(req.body,(err,docs) => {
        callback(err,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": [
        "动作","犯罪"
    ],}
const movieInfo1 = {
    "title": 'movie1',"爱情"
    ],}

测试代码

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

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...