sailsjs框架用了一段时间了,感觉如果功能复杂了,非常难以处理,想用一下单元测试,看是否能解决问题。
    sailsjs的官方文档使用的是mocha,我搜索了一些资料,主要参考了朴灵的《深入浅出nodejs》的单元测试一章、sailsjs的官方文档以及github上的一个例子https://github.com/bredikhin/sailsjs-mocha-testing-barrels-fixtures-example
    1)系统环境如下
          Windows 8.1 X64
          nodejs 0.12.1
          sailsjs  0.11.0
     2)安装过程
          需要安装mocha和should,mocha是测试框架,should是一个断言,也可以使用原生的assert,supertest是用来测试http请求的,这里用来测试controller
         npm install mocha -g
         npm install should
         npm install supertest
         其中mocha的主页为http://mochajs.org/,should的主页是https://www.npmjs.com/package/should,可以从这些网站找到相关的文档。
         mocha是安装为全局命令的,可以直接在命令行运行mocha,其参数较多,可以用mocha --help查看一下参数。
    3)目录和文件准备
./myApp
├── api
├── assets
├── ...
├── test
│ ├── unit
│ │ ├── controllers
│ │ │ └── UserController.test.js
│ │ ├── models
│ │ │ └── User.test.js
│ │ └── ...
│ ├── fixtures
│ ├── ...
│ ├── bootstrap.test.js
│ └── mocha.opts
└── views

首先在根目录下建立test目录,然后一次建立test\unit\controllers和test\unit\models目录。

       然后在test下建立文件bootstrap.test.js,这个文件是用来启动sailsjs程序的,也可以说是配置环境的,内容如下
var Sails = require('sails'),
sails;
 
before(function (done) {
 Sails.lift({
  log : {
   level : 'error'   //指定错误级别,避免出现调试输出,这主要是用来调试controller
  }
 }, function (err, server) {
  sails = server;
  if (err)
   return done(err);
  // here you can load fixtures, etc.
  done(err, sails);
 });
});
 
after(function (done) {
 var done_called = false;
 Sails.lower(function () {
  if (!done_called) {
   done_called = true;
   setTimeout(function () {
    sails.log.debug("inside app.lower, callback not called yet. calling.");
    done();
   }, 1000);
  } else {
   sails.log.debug("inside app.lower, callback already called.");
  }
 });
});
需要注意的是,after()和官方文档的不一致,因为会出现done()调用多次的问题,所以我参考了网上的一个资源,增加了等待。

4)测试控制器(controller)

 

在test\unit\controllers下建立UserController.test.js,内容如下

var request = require('supertest');

var should = require('should');

describe('UsersController', function () {

describe('#login()', function () {

it('should get 1', function (done) {

request(sails.hooks.http.app)

.get('/user/login?login_code=12345678901&user_password=111111')

.end(function (err, results) {

should(results.res.body.result).be.exactly(1);

done();

});

});

});

});

这里用的是BDD的风格,我比较喜欢这种方式,也可以采用TDD的风格,感觉都差不多

上面的代码也很简单,对/user/login?login_code=12345678901&user_password=111111发起请求,根据返回内容进行判断,这里要注意一下,返回的信息要多于通常的返回,比如我的返回是类似于{result: 1, desc:'登录成功'}之类的,但是supertest返回的要多得多,所以用result.res.body.result才能得到result值,也可以将信息打印出来看一下,不过需要注意的是因为前面设置了log:{level: 'error'},可以看不到输出,可以将error改成info,再试一下。

5)运行测试

    mocha -t 10000 test/bootstrap.test.js test/unit/**/*.test.js
    也可以在package.json中的scripts下增加npm命令,如下
"scripts": {
    "start": "node app.js",
    "debug": "node debug app.js",
 "test": "mocha -t 10000 test/bootstrap.test.js test/unit/**/*.test.js"
  },
这样就可以直接运行npm test执行测试了。
需要说明一下, -t 10000代表每个测试的执行时间增加到10秒,默认是2秒,在我的系统上无法返回,会出现错误,可能我的机器太慢了吧。
如果用户名密码正确,则返回
 1 passing (7s)
         如果出现错误,则返回
  0 passing (6s)
  1 failing
  1) UsersController #login() should get 1:
      Uncaught AssertionError: expected 0 to be 1
      + expected - actual
      -0
      +1
      at Test.<anonymous> (D:\work\nodejs\KangfuMobile\test\unit\controllers\Use rController.test.js:13:40) 
      at net.js:1392:10
       所以用来测试controller是非常简单的,
6)测试逻辑,在test\unit\models建立User.test.js,内容为
var should = require('should');
var bcrypt = require('bcrypt');
 
describe('用户表', function () {
 describe('查找用户信息', function () {
  it('应该检查用户表是否没有这个用户了', function (done) {
   User.find({
    user_code : '12345678901'
   }).exec(function (err, results) {
    should(results.length).be.exactly(1);
    done();
   });
  });
 });
 describe('查找用户名密码', function () {
  it('应该检查密码是否录入错误,或者密码加密系统出现错误', function (done) {
   User.findOne({
    user_code : '12345678901'
   }).exec(function (err, user) {
    var user_password = '111111';
    var user_password_o = user.user_password;
    user_password_o = "$2a$" + user_password_o.substr(4);
    bcrypt.compare(user_password, user_password_o, function (err, comp) {
     should(comp).be.exactly(true);
     done();
    });
 
   });
  });
 });
});
上面有两个测试,一个是查看是否存在且只有一个用户名为“12345678901”的用户,第二个是查看其密码是否正确。
运行测试命令,得到如下结果,如果没有用户,则会出现下面的错误:
  2 passing (6s)
  3 failing
 
  1) UsersController #login() should get 1:
 
      Uncaught AssertionError: expected 0 to be 1
      + expected - actual
 
      -0
      +1
 
      at Test.<anonymous> (D:\work\nodejs\KangfuMobile\test\unit\controllers\Use rController.test.js:13:40) 
      at net.js:1392:10
 
  2) 用户表 查找用户信息 应该检查用户表是否没有这个用户了:
 
      Uncaught AssertionError: expected 0 to be 1
      + expected - actual
 
      -0
      +1
 
      at D:\work\nodejs\KangfuMobile\test\unit\models\Users.test.js:10:31
      at readableAddChunk (_stream_readable.js:163:16)
      at Socket.Readable.push (_stream_readable.js:126:10)
      at TCP.onread (net.js:529:20)
 
  3) 用户表 查找用户名密码 应该检查密码是否录入错误,或者密码加密系统出现错误:
     Uncaught TypeError: Cannot read property 'user_password' of undefined
      at D:\work\nodejs\KangfuMobile\test\unit\models\Users.test.js:21:31
      at readableAddChunk (_stream_readable.js:163:16)
      at Socket.Readable.push (_stream_readable.js:126:10)
      at TCP.onread (net.js:529:20)
通过上面就可以查看是否出现了错误,并检查可能的问题,如果修改正确了,就会
        5 passing (6s)
7)基本来说,单元测试的基本内容就清楚了,不过想要更好的使用,还需要学会如何使用断言,比如should,还需要学习supertest的语法,mocha的BDD风格倒是非常简单,就是
    describe('测试内容',function(){
           describe('测试内容1', function(){
               it('需要注意什么', function(done){
                       //做测试
                       done();
               })
            })
    })
    如果用过async框架,就会对done()的使用非常熟悉了,这主要是用来处理异步问题的,等到done()返回才算测试结束了。
     should的使用非常简单,可以参考官方文档,也可以看看牛人写的例子:https://github.com/shouldjs/examples

NodeJs学习笔记(四)---单元测试的更多相关文章

  1. nodejs学习笔记<四>处理请求参数

    在web开发中处理请求参数是个非常常见的工作:nodejs提供了了querystring用来处理请求参数. querystring常用方法有:parse,stringify. (1)parse: 解析 ...

  2. NodeJS学习笔记四

    Generator简介 基本概念 Generator函数有多种理解角度.从语法上,首先可以把它理解成,Generator函数是一个状态机,封装了多个内部状态. 执行Generator函数会返回一个遍历 ...

  3. nodejs学习笔记四(模块化、在npm上发布自己的模块)

    模块化:      1.系统模块:  http.querystring.url      2.自定义模块      3.包管理器   [系统模块]   Assert      断言:肯定确定会出现的情 ...

  4. nodejs学习笔记四——express-session

    博友沉沉-_-的这篇express 框架之session分析的已经非常详细了,本人这里就不描述了. 总结其中的几个关键点. 1.http协议规定http链接是无状态的链接,cookie和session ...

  5. Nodejs学习笔记(四)——支持Mongodb

    前言:回顾前面零零碎碎写的三篇挂着Nodejs学习笔记的文章,着实有点名不副实,当然,这篇可能还是要继续走着离主线越走越远的路子,从简短的介绍什么是Nodejs,到如何寻找一个可以调试的Nodejs ...

  6. NodeJS学习笔记 进阶 (12)Nodejs进阶:crypto模块之理论篇

    个人总结:读完这篇文章需要30分钟,这篇文章讲解了使用Node处理加密算法的基础. 摘选自网络 Nodejs进阶:crypto模块之理论篇 一. 文章概述 互联网时代,网络上的数据量每天都在以惊人的速 ...

  7. C#可扩展编程之MEF学习笔记(四):见证奇迹的时刻

    前面三篇讲了MEF的基础和基本到导入导出方法,下面就是见证MEF真正魅力所在的时刻.如果没有看过前面的文章,请到我的博客首页查看. 前面我们都是在一个项目中写了一个类来测试的,但实际开发中,我们往往要 ...

  8. Nodejs学习笔记(三)——一张图看懂Nodejs建站

    前言:一条线,竖着放,如果做不到精进至深,那就旋转90°,至少也图个幅度宽广. 通俗解释上面的胡言乱语:还没学会爬,就学起走了?! 继上篇<Nodejs学习笔记(二)——Eclipse中运行调试 ...

  9. Nodejs学习笔记(二)——Eclipse中运行调试Nodejs

    前篇<Nodejs学习笔记(一)——初识Nodejs>主要介绍了在搭建node环境过程中遇到的小问题以及搭建Eclipse开发Node环境的前提步骤.本篇主要介绍如何在Eclipse中运行 ...

  10. NodeJS学习笔记之Connect中间件模块(一)

    NodeJS学习笔记之Connect中间件模块(一) http://www.jb51.net/article/60430.htm NodeJS学习笔记之Connect中间件模块(二) http://w ...

随机推荐

  1. Java多线程学习之wait、notify/notifyAll 详解

    1.wait().notify/notifyAll() 方法是Object的本地final方法,无法被重写. 2.wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关 ...

  2. Vocabulary & Phrase

    Vocabulary A ANSI    美国国家标准学会,American National Standards Institute的缩写 a couple of    [口语]少数的,几个 a s ...

  3. tsung压力测试——tcp测试tsung.xml配置模版说明

    <?xml version="1.0"?> <!DOCTYPE tsung SYSTEM "/usr/local/share/tsung/tsung-1 ...

  4. C# 跨平台的支付类库ICanPay

    随着微软的开源,越来越多的项目支持跨平台,但是各种支付平台提供的类库,又老又不支持跨平台,吐槽下,尤其是微信,还有好多坑,于是ICanPay诞生了,今天就来讲ICanPay是什么,怎么使用? ICan ...

  5. geotrellis使用(三十五)Cesium加载geotrellis TMS瓦片

    前言 做任何事情都不是想象中的那么简单.好久没有更新技术博客了,跟最近瞎忙有很大关系,虽说是瞎忙也抽空研究了些技术. 主要是前端渲染,像原生的WebGL和Cesium.WebGL写了几篇博客,自我感觉 ...

  6. CCLuaObjcBridge - Lua 与 Objective-C 互操作的简单解决方案

    http://dualface.github.io/blog/2013/01/27/call-objectivec-from-lua/ 月初的时候,发了一篇关于 Lua 与 Java 互操作的文章,里 ...

  7. JDK8新特性一览

    转载自:http://blog.csdn.net/qiubabin/article/details/70256683 官方新特性说明地址 Jdk8新特性.png 下面对几个常用的特性做下重点说明. 一 ...

  8. 0:A+B Problem-poj

    0:A+B Problem 总时间限制:  1000ms 内存限制:  65536kB 描述 Calculate a + b 输入 Two integer a,,b (0 ≤ a,b ≤ 10) 输出 ...

  9. 第六届蓝桥杯软件类省赛题解C++/Java

    第六届蓝桥杯软件类省赛题解C++/Java 1[C++].统计不含4的数字统计10000至99999中,不包含4的数值个数.答:暴力循环范围内所有数字判断一下就是了,答案是52488 1[Java]. ...

  10. 微服务配置内容《网上copy》=========》如何创建一个高可用的服务注册中心

    前言:首先要知道什么是一个高可用的服务注册中心,基于spring boot建成的服务注册中心是一个单节点的服务注册中心,这样一旦发生了故障,那么整个服务就会瘫痪,所以我们需要一个高可用的服务注册中心, ...