带你入门带你飞Ⅱ 使用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
带你入门带你飞Ⅱ 使用Mocha + Chai + SuperTest测试Restful API in node.js的更多相关文章
- 使用 TypeScript & mocha & chai 写测试代码实战(17 个视频)
		使用 TypeScript & mocha & chai 写测试代码实战(17 个视频) 使用 TypeScript & mocha & chai 写测试代码实战 #1 ... 
- 带你入门带你飞Ⅰ 使用Mocha + Chai + Sinon单元测试Node.js
		目录 1. 简介 2. 前提条件 3. Mocha入门 4. Mocha实战 被测代码 Example 1 Example 2 Example 3 5. Troubleshooting 6. 参考文档 ... 
- #单元测试#以karma+mocha+chai 为测试框架的Vue webpack项目(二)
		学习对vue组件进行单元测试,先参照官网编写组件和测试脚本. 1.简单的组件 组件无依赖,无props 对于无需导入任何依赖,也没有props的,直接编写测试案例即可. /src/testSrc/si ... 
- #单元测试#以karma+mocha+chai 为测试框架的Vue webpack项目(一)
		目标: 为已有的vue项目搭建 karma+mocha+chai 测试框架 编写组件测试脚本 测试运行通过 抽出共通 一.初始化项目 新建项目文件夹并克隆要测试的已有项目 webAdmin-web 转 ... 
- node.js入门基础
		内容: 1.node.js介绍 2.node.js内置常用模块 3.node.js数据交互 一.node.js介绍 (1)node.js特点 与其他语言相比,有以下优点: 对象.语法和JavaScri ... 
- 极简 Node.js 入门 - Node.js 是什么、性能有优势?
		极简 Node.js 入门系列教程:https://www.yuque.com/sunluyong/node 本文更佳阅读体验:https://www.yuque.com/sunluyong/node ... 
- DTSE Tech Talk | 第10期:云会议带你入门音视频世界
		摘要:本期直播主题是<云会议带你入门音视频世界>,华为云媒体服务产品部资深专家金云飞,与开发者们交流华为云会议在实时音视频行业中的集成应用,帮助开发者更好的理解华为云会议及其开放能力. 本 ... 
- 可能是史上最强大的js图表库——ECharts带你入门
		PS:之前的那篇博客Highcharts——让你的网页上图表画的飞起 ,评论中,花儿笑弯了腰 和 StanZhai 两位仁兄让我试试 ECharts ,去主页看到<Why ECharts ?&g ... 
- 史上最强大的js图表库——ECharts带你入门(转)
		出处:http://www.cnblogs.com/zrtqsk/p/4019412.html PS:之前的那篇博客Highcharts——让你的网页上图表画的飞起 ,评论中,花儿笑弯了腰 和 Sta ... 
随机推荐
- 配置自己的OpenGL库,glew、freeglut库编译,库冲突解决(附OpenGL Demo程序)
			平台:Windows7,Visual C++ 2010 1. 引言 实验室的一个项目,用到OpenGL进行实时绘制,还用到一些其他的库,一个困扰我很久的问题就是编译时遇到的各种符号未定义,符号重定义之 ... 
- js中的break ,continue, return (转)
			面向对象编程语法中我们会碰到break ,continue, return这三个常用的关键字,那么关于这三个关键字的使用具体的操作是什么呢?我们在使用这三关键字的时候需要注意和需要理解的规则是什么呢? ... 
- LintCode Merge Sorted Array
			两个排好序的数组, A有m个数, 长度够长, B有n个数, 长度为n, 将B放到A里, 不用buffer数组(临时数组), 就用A将两个合在一起, 同时排好序. 方法: 从右边将两个数组里最大的数取出 ... 
- wininet异步InternetReadFile和超时相关问题
			wininet是对socket的封装 主要流程为创建,连接,发送,接收,关闭几个过程 所以在回调函数InternetStatusCallback中可以检测到dwInternetStatus #defi ... 
- Android Sqlite数据库加密
			Android使用的是开源的SQLite数据库,数据库本身没有加密,加密思路通常有两个: 1. 对几个关键的字段使用加密算法,再存入数据库 2. 对整个数据库进行加密 SQLite数据库加密工具: 收 ... 
- OS实验报告——作业调度模拟程序
			一.目的和要求 1. 实验目的 (1)加深对作业调度算法的理解: (2)进行程序设计的训练. 2.实验要求 用高级语言编写一个或多个作业调度的模拟程序. 单道批处理系统的作业调度程序.作业一投入运行, ... 
- 实验1_IPv6地址配置
			IPv6地址配置 实验任务 (1)掌握如何在路由器及PC上配置IPv6地址 (2)掌握如何用IPv6 ping命令进行IPv6地址可达性检查 (3)掌握如何用命令来查看IPv6地址配置 实验过程 在R ... 
- 另类vs2015+xamarin 的android界面乱码 解决
			text.Text += "验证key 验证出错! 请在 AndroidManifest.xml 文件中检查 key 设置"; 代码就上面一行,单步走之前text.Text里面是汉 ... 
- Java中避免表单重复提交
			表单的重复提交: 没有完整的进行一次,先请求表单页面->再提交表单过程而完成数据提交 造成的根本原因: 没有完整的进行一次,先请求表单页面->再提交表单过程. 造成重复提交的现象: 由于服 ... 
- c# List去重
			1 list如果数据是值类型,比如list<int> 这种,添加linq之后就可以使用list = list.Distinct().ToList(); 2 如果是数据是引用类型,比如中间是 ... 
