相关文章推荐
阳光的胡萝卜  ·  Android Studio ...·  1 年前    · 
含蓄的葡萄酒  ·  Python : ...·  1 年前    · 

教程内容

采用测试驱动开发的方式,开发一个简单的 REST API,包括基本的 POST/GET/PUT/DELETE 操作

先编写好针对各个接口的测试代码,包括:

  1. 调用post接口插入一个对象

  2. 调用get接口获取某个对象的数据

  3. 调用get接口获取集合数据

  4. 调用put接口更新某个对象数据

  5. 调用get接口获取更新后的对象

  6. 调用delete接口删除对象

然后针对第一个测试进行代码编写,写完后执行测试,第一个测试通过后,继续开发下一个,再进行测试,这样迭代进行

测试框架采用 Mocha,WEB框架采用 Express.js 4,数据库使用 MongoDB

前期准备

安装好 Nodejs,Mongodb,配置好npm镜像

我使用的是:nvm 安装 nodejs、Mongodb Docker 镜像、淘宝的cnpm镜像,还安装了 supervisor(检测代码变更,自动加载)

创建项目

创建一个目录 test-rest-api ,然后在命令行下进入此目录

安装依赖

npm install mocha --save-dev
npm install expect.js --save-dev 
npm install superagent --save-dev
npm install express --save
npm install mongo --save
npm install mongoskin --save
npm install body-parser --save

新建代码文件

  • express.js - api 代码

  • express.test.js - 测试代码

编写测试

express.test.js 内容:

var superagent = require('superagent')
var expect = require('expect.js')
var mongoskin = require('mongoskin')
var db = mongoskin.db('mongodb://@localhost:27017/test-rest', { safe: true })
describe('express rest api server', function() {
    // 测试执行前清空数据库    before(function() {        db.collection('test').remove({})    var id    // --- 测试 post
   it('post object', function(done) {        superagent.post('http://localhost:3000/collections/test')            .send({                name: 'Johns',                email: 'john@rpjs.co'            .end(function(e, res) {                // console.log(res.body)                expect(e).to.eql(null)                expect(res.body.ops.length).to.eql(1)                expect(res.body.ops[0]._id.length).to.eql(24)                id = res.body.ops[0]._id                done()    // --- 测试 get by ID    it('retrieves an object', function(done) {        superagent.get('http://localhost:3000/collections/test/' + id)            .end(function(e, res) {                // console.log(res.body)                expect(e).to.eql(null)                expect(typeof res.body).to.eql('object')                expect(res.body._id.length).to.eql(24)                expect(res.body._id).to.eql(id)                done()    })
   // --- 测试 get 集合    it('retrieves a collection', function(done) {        superagent.get('http://localhost:3000/collections/test')            .end(function(e, res) {                // console.log(res.body)                expect(e).to.eql(null)                expect(res.body.length).to.be.above(0)                expect(res.body.map(function(item) {                    return item._id                })).to.contain(id)                done()    })
   // --- 测试 update 更新
       it('updates an object', function(done) {        superagent.put('http://localhost:3000/collections/test/' + id)            .send({                name: 'Peter',                email: 'peter@yahoo.com'            .end(function(e, res) {                expect(e).to.eql(null)                done()    })
   
   // --- 验证更新后的数据    it('checks an updated object', function(done) {        superagent.get('http://localhost:3000/collections/test/' + id)            .end(function(e, res) {                // console.log(res.body)                expect(e).to.eql(null)                expect(typeof res.body).to.eql('object')                expect(res.body._id.length).to.eql(24)                expect(res.body._id).to.eql(id)                expect(res.body.name).to.eql('Peter')                done()    })
   
   // --- 测试 remove 删除    it('removes an object', function(done) {        superagent.del('http://localhost:3000/collections/test/' + id)            .end(function(e, res) {                // console.log(res.body)                expect(e).to.eql(null)                expect(res.body.msg).to.eql('success')                done() })

运行测试

./node_modules/mocha/bin/mocha express.test.js

运行的结果一定是全部失败,因为还没有编写实际代码,下面就编写代码,使测试一个个的通过。

编写api

express.js 内容:

var express = require('express'),
  mongoskin = require('mongoskin'),
  bodyParser = require('body-parser')  
var app = express()
app.use(bodyParser())
var db = mongoskin.db('mongodb://@localhost:27017/test-rest', {safe:true})
app.param('collectionName', function(req, res, next, collectionName){
  req.collection = db.collection(collectionName)
  return next()
app.get('/', function(req, res) {
  res.send('欢迎')
// --- 后续功能代码区域
// -----------------
app.listen(3000)

上面是最基础的代码,连接到了数据库,启动了http服务

运行

node express.js

如果安装了 supervisor,就使用它来启动,之后改动 express.js 的话就不用重新启动了

supervisor express.js

启动后使用浏览器访问

http://localhost:3000/

可以看到欢迎信息,基础做好了,开始编写功能代码

添加 post 创建对象

在功能代码区添加:

app.post('/collections/:collectionName', function(req, res, next) {
  req.collection.insert(req.body, {}, function(e, results){
    if (e) return next(e)
    res.send(results)
})

如果没使用 supervisor,记得重新执行 node express.js

执行测试

./node_modules/mocha/bin/mocha express.test.js

测试运行结果:

  express rest api server
    ✓ post object (41ms)
    1) retrieves an object
    2) retrieves a collection
    3) updates an object
    4) checks an updated object
    5) removes an object
  1 passing (81ms)
  5 failing

post 功能通过了

添加 get 根据ID取得对象信息

app.get('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.findById(req.params.id, function(e, result){
    if (e) return next(e)
    res.send(result)
})

重启、测试,结果:

  express rest api server
    ✓ post object (97ms)
    ✓ retrieves an object
    1) retrieves a collection
    2) updates an object
    3) checks an updated object
    4) removes an object
  2 passing (179ms)
  4 failing

添加 get 获取集合数据

app.get('/collections/:collectionName', function(req, res, next) {
  req.collection.find({} ,{limit:10, sort: [['_id',-1]]}).toArray(function(e, results){
    if (e) return next(e)
    res.send(results)
})

重启、测试,结果:

  express rest api server
    ✓ post object (90ms)
    ✓ retrieves an object
    ✓ retrieves a collection
    1) updates an object
    2) checks an updated object
    3) removes an object
  3 passing (179ms)
  3 failing

添加 update 根据ID修改对象数据

app.put('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.updateById(req.params.id, {$set:req.body}, function(e, result){
    if (e) return next(e)
    res.send(result)
})

重启、测试,结果:

  express rest api server
    ✓ post object (128ms)
    ✓ retrieves an object
    ✓ retrieves a collection
    ✓ updates an object
    ✓ checks an updated object
    1) removes an object
  5 passing (230ms)
  1 failing

添加 delete 根据ID删除对象

app.del('/collections/:collectionName/:id', function(req, res, next) {
  req.collection.removeById(req.params.id, function(e, result){
    if (e) return next(e)
    res.send((result===1)?{msg:'success'}:{msg:'error'})
})

重启、测试,结果:

  express rest api server
    ✓ post object (40ms)
    ✓ retrieves an object
    ✓ retrieves a collection
    ✓ updates an object
    ✓ checks an updated object
    ✓ removes an object
  6 passing (103ms)

这样,所有测试都就通过了,代码开发完成

小结

通过这个小例子,可以了解nodejs express的开发方式,并体验了测试驱动的开发方法