zoukankan      html  css  js  c++  java
  • 带你入门带你飞Ⅱ 使用Mocha + Chai + SuperTest测试Restful API in node.js

    目录
      1. 简介
      2. 准备开始
      3. Restful API测试实战
          Example 1 - GET
          Example 2 - Post
          Example 3 - Put
          Example 4 - Delete
      4. Troubleshooting
      5. 参考文档

    简介

    经过上一篇文章的介绍,相信你已经对mocha, chai有一定的了解了, 本篇主要讲述如何用supertest来测试nodejs项目中的Restful API, 项目基于express框架。

    SuperTest 是 SuperAgent一个扩展, 一个轻量级 HTTP AJAX 请求库.

    SuperTest provides high-level abstractions for testing node.js API endpoint responses with easy to understand assertions.

    准备开始

    npm安装命令

    npm install supertest

     

    nodejs项目文件目录结构如下

    ├── config
    │   └── config.json
    ├── controllers
    │   └── dashboard
    │       └── widgets
    │           └── index.js
    ├── models
    │   └── widgets.js
    ├── lib
    │   └── jdbc.js
    ├── package.json
    └── test
        └── controllers
            └── dashboard
                └── widgets
                    └── index_IntegrationTest.js 

    测试代码写在index_IntegrationTest.js这个文件中

    Restful API测试实战

    测试依赖库

    var express = require('express');
    var kraken = require('kraken-js');
    var request = require('supertest');
    var chai = require('chai');
    var assert = chai.assert;

    ##转载注明出处:http://www.cnblogs.com/wade-xu/p/4673460.html 

    Example 1 - GET

    Controller/dashboard/widgets/index.js

    var _widgets = require('../../../models/widgets.js');
    
    module.exports = function(router) {
    
      router.get('/', function(req, res) {
        _widgets.getWidgets(req.user.id)
                .then(function(widgets){
                  return res.json(widgets);
                })
                .catch(function(err){
                  return res.json ({
                    code: '000-0001',
                    message: 'failed to get widgets:'+err
                  });
                });
      });
    };

    测试代码:

    var kraken = require('kraken-js');
    var express = require('express');
    var request = require('supertest');
    var aweb = require('acxiom-web');
    var chance = new(require('chance'))();
    var chai = require('chai');
    var assert = chai.assert;
    
    describe('/dashboard/widgets', function() {
    
      var app, mock;
    
      before(function(done) {
        app = express();
        app.on('start', done);
    
        app.use(kraken({
          basedir: process.cwd(),
          onconfig: function(config, next) {
            //some config info
    
            next(null, config);
          }
        }));
    
        mock = app.listen(1337);
    
      });
    
      after(function(done) {
        mock.close(done);
      });
    
      it('get widgets', function(done) {
        request(mock)
          .get('/dashboard/widgets/')
          .set('Accept', 'application/json')
          .expect(200)
          .expect('Content-Type', 'application/json; charset=utf-8')
          .end(function(err, res) {
            if (err) return done(err);
            assert.isArray(res.body, 'return widgets object');
            done();
          });
      });
    
    });

    Example 2 - Post

    被测代码:

      router.post('/', function(req, res) {
        _widgets.addWidget(req.user.id, req.body.widget)
                .then(function(widget){
                  return res.json(widget);
                })
                .catch(function(err){
                  return res.json ({
                    code: '000-0002',
                    message: 'failed to add widget:' + err
                  });
                });
      });

    测试代码:

      it('add widgets', function(done) {
       var body = {
        widget: {
        type: 'billing',
        color: 'blue',
        location: {
            x: '1',
            y: '5'
          }
         }
        };
    
        request(mock)
          .post('/dashboard/widgets/')
          .send(body)
          .expect(200)
          .expect('Content-Type', /json/)
          .end(function(err, res) {
            if (err) return done(err);
            assert.equal(res.body.type, 'billing');
            assert.equal(res.body.color, 'blue');
            done();
          });
      });

    ##转载注明出处:http://www.cnblogs.com/wade-xu/p/4673460.html 

    Example 3 - Put

    被测代码

      router.put('/color/:id', function(req, res) {
        _widgets.changeWidgetColor(req.params.id, req.body.color)
                .then(function(status){
                  return res.json(status);
                })
                .catch(function(err){
                  return res.json ({
                    code: '000-0004',
                    message: 'failed to change widget color:' + err
                  });
                });
      });

    测试代码

      describe('change widget color', function() {
        var id = '';
        before(function(done) {
          var body = {
            widget: {
              type: 'billing',
              color: 'blue',
              location: {
                x: '1',
                y: '5'
              }
            }
          };
    
          request(mock)
            .post('/dashboard/widgets/')
            .send(body)
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function(err, res) {
              if (err) return done(err);
              id = res.body.id;
              done();
            });
    
        });
    
        it('change widget color to white', function(done) {
          var body = {
            color: 'white'
          };
    
          request(mock)
            .put('/dashboard/widgets/color/' + id)
            .send(body)
            .expect(200)
            .expect({
              status: 'success'
            })
            .expect('Content-Type', /json/)
            .end(function(err, res) {
              if (err) return done(err);
              done();
            });
        });
      });

    在这个测试case中,前提是要先create 一个widget, 拿到id之后你才可以针对这个刚创建的widget修改, 所以在it之前用了 before 做数据准备。

    Example 4 - Delete

    被测代码

      router.delete('/:id', function(req, res) {
        _widgets.deleteWidget(req.user.id, req.params.id)
                .then(function(status){
                  return res.json(status);
                })
                .catch(function(err){
                  return res.json ({
                    code: '000-0003',
                    message: 'failed to delete widget:' + err
                  });
                });
      });

    测试代码

      describe('delete widget', function() {
        var id = '';
        before(function(done) {
          var body = {
            widget: {
              type: 'billing',
              color: 'blue',
              location: {
                x: '1',
                y: '5'
              }
            }
          };
    
          request(mock)
            .post('/dashboard/widgets/')
            .send(body)
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function(err, res) {
              if (err) return done(err);
              id = res.body.id;
              done();
            });
    
        });
    
        it('delete a specific widget', function(done) {
          request(mock)
            .del('/dashboard/widgets/' + id)
            .expect(200)
            .expect('Content-Type', /json/)
            .end(function(err, res) {
              if (err) return done(err);
              assert.deepEqual(res.body, {
                status: 'success'
              });
              done();
            });
        });
      });

    注意这里用的是del 不是 delete, Supertest提供的delete方法是del, 不是delete

    ##转载注明出处:http://www.cnblogs.com/wade-xu/p/4673460.html 

    测试结果如下:

    Troubleshooting

     1. 当你用request().delete() 时报错TypeError: undefined is not a function

    换成request().del()

      

    参考文档

    Mocha: http://mochajs.org/

    Chai: http://chaijs.com/

    SuperTest: https://www.npmjs.com/package/supertest

    感谢阅读,如果您觉得本文的内容对您的学习有所帮助,您可以点击右下方的推荐按钮,您的鼓励是我创作的动力。

    ##转载注明出处:http://www.cnblogs.com/wade-xu/p/4673460.html 

  • 相关阅读:
    ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client
    JavaScript 的 if else 和 switch对比
    setTimeout 、 promise、async await 的执行顺序?宏任务、微任务,分别包含哪些?
    mac终端,自定义命令提示符。zsh导致PS1变量序列字符失效!!!
    js基础——错误处理
    Nginx | CentOS 8 安装Nginx详细教程
    Vue | 虚拟DOM
    Vue | 双向数据绑定
    Hexo | 超详细的hexo+githhub page搭建过程
    JavaScript | 彻底搞懂JS闭包
  • 原文地址:https://www.cnblogs.com/wade-xu/p/4673460.html
Copyright © 2011-2022 走看看