静,是一种休息,更是一种修行。所有的烦恼,都来自于喧嚣,所有的伤痛,都来自于躁动。身体奔波太久会劳累,灵魂游离太久会成伤。红尘淹没了纯洁,欲望吞噬了安详,经年后,心若一动,泪已千行。 停一停追逐的脚步,缓一缓紧绷的心弦,让心宁静,让伤口复原,让灵魂升华。

单元测试工具Mocha和SuperTest

王海峰 | 发表于:2016-07-19 20:15:10 | 日志分类:测试开发 | 阅读量:(672)
一、技术背景

Mocha 是一个能让异步测试变得很简单的 javascript 测试框架。 选用它的原因:Mocha 既可以在 node.js 环境中运行,也可以运行在浏览器中。与其它的 javascript 测试框架比较起来,我们发现 Mocha 对于异步测试的处理是我们选择它的关键因素。当进行 API 测试时,我们会发送一些数据到终端,并且使用返回的数据向另一个终端发起调用请求。例如,我需要先获取到一个用户的数据,然后通过该用户的 id 获取到所有属于他的位置信息。

Chai 与 Jasmine 不同,要让 Mocha 工作起来还需要额外的断言库。Chai 就是一个断言库,它可以让选择你最喜欢的接口,包括 “assert”,“expect” 还有 “should”。 选用它的原因:尽管 Mocha 可以与任意的断言库一起使用,Chai 也可以被任意的测试库所使用,但是许多 javascript 开发者还是选择将两者搭配使用。我们使用了 Chai 的 “expect” 接口将断言串联起来,这样我们就可以彻底的测试从 API 终端返回的 JSON 数据了。对于和我一样,有使用过 RSpec 的 ruby 程序员来说,Chai 非常容易上手,因为它的断言语法与 RSpec 的非常接近。
SuperTest 是 SuperAgent 的一个扩展,一个轻量级的 HTTP AJAX 请求库。SuperTest 提供了用于测试 node.js API 终端响应的高阶抽象,使得断言便于理解。
选用它的原因:除了测验 JSON 对象的内容外,我们还想测验终端响应的其它数据,包括头信息类型和响应状态码。SuperTest 还有一个漂亮直观的接口。只需要简单地将接口终端需要的数据发送过去,就可以检验响应了。

二、Mocha
Mocha是非常流行JavaScript测试框架之一,在浏览器和Node环境都可以使用。这里主要是针对Node环境。
1、如何开始安装
使用 npm 安装 Mocha
npm install -g mocha
这样会全局安装 Mocha。
使用 npm 安装 Chai
npm install chai
使用 npm 安装 SuperTest
npm install supertest
使用 npm 安装 Express
npm install express
使用 npm 安装 Body-Parser
npm install Body-Parser

设置你的测试目录
使用你的终端,进入你的项目所在目录,然后用 mkdir test 指令新建一个测试目录。测试目录必须命名为 test ,这样 Mocha 才能找到所需执行的测试文件。
创建你的第一个文件
你可以给你的 mocha 文件起任意的名称。不过,如果你有成组的业务模型需要针对多个终端进行测试,那么我建议将它们命名为 “yourModel_test.js” 这种形式。这个例子里,就在 test 目录下新建一个 test.js 文件好了。
引用代码库
在测试文件开始,我们引入每一个要使用到的库,并将其赋值给一个全局变量。


2、使用
下面我就来介绍一下Mocha的语法了,首先我把我本次的示例代码奉上。
然后就是Mocha的语法了。首先来看一下最简单例子:
// 这是一个简单的加法函数


现在用Mocha写一个测试脚本去测试这个函数。一般来说,测试脚本的命名要和测试的模块一致,后缀为.test.js。这里测试脚本的名称为add.test.js,表示对add模块进行测试。


然后保存代码之后进入终端,执行mocha add.test 即可。其中describe()函数是测试描述,表示一组相关测试用例是对哪个模块的测试。
it()是一个测试用例,在一个describe块的内部可以执行对个测试用例(it块)。

这是同步函数的测试。在Node环境中,绝大部分的业务逻辑都是异步的,所以测试结果的回调是JavaScript测试框架需要解决的首要问题。

Mocha提供了一个回调函数done,在业务代码执行完毕之后调用done()结束测试用例,不然的话测试用例就会出现timeout的情况导致测试用例失败。
Mocha默认的超时时间是2000毫秒,如果由于测试用例的执行时间比较长需要延长超时时间,可以在命令行添加 -t 参数,比如mocha -t 3000 add.test.js。
当然还有其他命令行参数,比如 mocha -w 用来监视指定的测试脚本。只要测试脚本有变化,就会自动运行Mocha。查看更多的命令行参数可以通过 mocha -h 查找。

那么接下来看一个异步测试例子:

在request请求执行完毕end()之后,一定要调用done(),否则测试用例超时,那么这个用例就失败了。
其中,所有的测试用例(it块)都应该含有一句或多句的断言,它是编写测试用例的关键。断言功能由断言库来实现,Mkcha本身不带断言库,所有必须先引入断言库
var expect = require('chai').expect;
上面的例子中,它出了检查出返回的结果是否是一个json对象,还会使用 Chai 的 expect 接口做一些额外的断言,因为相比 assert 和 should 接口我更喜欢 expect 一些

三、chai断言库

断言库有很多种,Mocha并不限制使用哪一种。上面代码引入的断言库是chai,并且指定使用它的expect断言风格。 expect断言的优点是很接近自然语言,下面是一些例子


基本上,expect断言的写法都是一样的。头部是expect方法,尾部是断言方法,比如equal、a/an、ok、match等。两者之间使用to或to.be连接。

如果expect断言不成立,就会抛出一个错误。事实上,只要不抛出错误,测试用例就算通过。

四、断言库should
Mocha本身是不包含断言库的,所以我们需要自己选择断言库。should是一个很简单的、贴近自然语言的断言库。当然,Mocha是适配所有的断言库的,如果你喜欢其他的断言库比如expect之类的,你也可以把它包含进来使用。
should的语法非常贴近自然语言,简单易懂,常见的should断言如下:

五、测试用例的钩子

Mocha在describe块之中,提供测试用例的四个钩子:before()after()beforeEach()afterEach()。它们会在指定时间执行。
有时候在集成测试中,你需要先创建一些记录然后再使用这些数据。只需要加入一个 before 方法你就可以很容易地达到这个目的。一定要把你的 before 方法写在 describe 方法内
describe('hooks', function() {
before(function() {
// 在本区块的所有测试用例之前执行
});
after(function() {
// 在本区块的所有测试用例之后执行
});
beforeEach(function() {
// 在本区块的每个测试用例之前执行
});
afterEach(function() {
// 在本区块的每个测试用例之后执行
});
// test cases
});


六、SuperTest
单单使用Mocha和should就几乎可以满足所有JavaScript函数的单元测试。但是对于Node应用而言,不仅仅是函数的集合,比如一个web应用的测试。这时候就需要配合一个http代理,完成Http请求和路由的测试。 Supertest是一个HTTP代理服务引擎,可以模拟一切HTTP请求行为。Supertest可以搭配任意的应用框架,从而进行应用的单元测试。
它具有以下特点:
  • 继承了superagent所有的API和用法。
  • 使用前需安装node,然后用npm install supertest --save-dev或者cnpm install supertest --save-dev安装supertest。
  • 和superagent一样,需要通过调用.end() 执行一个request请求。
  • 调用.expect()来做断言,如果在里面填入数字,默认是检查http请求返回的状态码;

其中,点击打开它的github地址进行实例下载。
下面是作者结合本网站的后台写的一个示例代码,有get 请求和post请求示例


分析上面的代码:
1、如果需要设置数据,supertest的API提供了 .set 来设置,比如这里通过.set('Accept', 'application/json')
2、.expect 是一个断言,上述测试代码在执行之后期望的状态码是200(OK)。如果接收到的数据为html页面,.expect('Content-Type', 'text/html;charset=utf-8')
3、.end 是执行一个request请求,在回调函数里面根据业务逻辑的返回数据做断言分析。
4、很多情况下,项目需要测试一个表单业务。supertest提供了.send()方法来发送表单域数据。比如一个登录模块,需要发送用户名密码: