关于[ES6 Promises](http://liubin.github.io/promises-book/#es6-promises)的语法我们已经学了一些, 我想大家应该也能够在实际项目中编写Promise 的Demo代码了吧。
这时,接下来你可能要苦恼该如何编写Promise 的测试代码了。
那么让我们先来学习下如何使用 [Mocha](http://mochajs.org/)来对Promise 进行基本的测试吧。
先声明一下,这章中涉及的测试代码都是运行在Node.js环境下的。
> 本书中出现的示例代码也都有相应的测试代码。 测试代码可以参考 [azu/promises-book](https://github.com/azu/promises-book) 。
## 3.1.1\. Mocha
Mocha是Node.js下的测试框架工具,在这里,我们并不打算对 [Mocha](http://mochajs.org/)本身进行详细讲解。对 [Mocha](http://mochajs.org/)感兴趣的读者可以自行学习。
Mocha可以自由选择BDD、TDD、exports中的任意风格,测试中用到的Assert 方法也同样可以跟任何其他类库组合使用。 也就是说,Mocha本身只提供执行测试时的框架,而其他部分则由使用者自己选择。
这里我们选择使用Mocha,主要基于下面3点理由。
* 它是非常著名的测试框架
* 支持基于Node.js 和浏览器的测试
* 支持"Promise测试"
最后至于为什么说 _支持"Promise测试"_ ,这个我们在后面再讲。
要想在本章中使用Mocha,我们需要先通过npm来安装Mocha。
~~~
$ npm install -g mocha
~~~
另外,Assert库我们使用的是Node.js自带的`assert`模块,所以不需要额外安装。
首先,让我们试着编写一个对传统回调风格的异步函数进行测试的代码。
## 3.1.2\. 回调函数风格的测试
如果想使用回调函数风格来对一个异步处理进行测试,使用Mocha的话代码如下所示。
basic-test.js
~~~
var assert = require('power-assert');
describe('Basic Test', function () {
context('When Callback(high-order function)', function () {
it('should use `done` for test', function (done) {
setTimeout(function () {
assert(true);
done();
}, 0);
});
});
context('When promise object', function () {
it('should use `done` for test?', function (done) {
var promise = Promise.resolve(1);
// このテストコードはある欠陥があります
promise.then(function (value) {
assert(value === 1);
done();
});
});
});
});
~~~
将这段代码保存为 `basic-test.js`,之后就可以使用刚才安装的Mocha的命令行工具进行测试了。
~~~
$ mocha basic-test.js
~~~
Mocha的 `it` 方法指定了 `done` 参数,在 `done()` 函数被执行之前, 该测试一直处于等待状态,这样就可以对异步处理进行测试。
Mocha中的异步测试,将会按照下面的步骤执行。
~~~
it("should use `done` for test", function (done) {
//回调式的异步处理
setTimeout(function () {
assert(true);
done();//调用`done` 后测试结束
}, 0);
});
~~~
这也是一种非常常见的实现方式。
## 3.1.3\. 使用`done` 的Promise测试
接下来,让我们看看如何使用 `done` 来进行Promise测试。
~~~
it("should use `done` for test?", function (done) {
var promise = Promise.resolve(42);//创建名为`Fulfilled` 的promise对象
promise.then(function (value) {
assert(value === 42);
done();//调用`done` 后测试结束
});
});
~~~
[`Promise.resolve`](http://liubin.github.io/promises-book/#Promise.resolve) 用来返回promise对象, 返回的promise对象状态为FulFilled。 最后,通过 `.then` 设置的回调函数也会被调用。
像[专栏: Promise只能进行异步操作?](http://liubin.github.io/promises-book/#promise-is-always-async) 中已经提到的那样, promise对象的调用总是异步进行的,所以测试也同样需要以异步调用的方式来编写。
但是,在前面的测试代码中,在`assert` 失败的情况下就会出现问题。
对异常promise测试
~~~
it("should use `done` for test?", function (done) {
var promise = Promise.resolve();
promise.then(function (value) {
assert(false);// => throw AssertionError
done();
});
});
~~~
在此次测试中 `assert` 失败了,所以你可能认为应该抛出“测试失败”的错误, 而实际情况却是测试并不会结束,直到超时。
![promise test timeout](https://box.kancloud.cn/2015-07-20_55ac765042f17.png)
Figure 7\. 由于测试不会结束,所以直到发生超时时间未知,一直会处于挂起状态。
通常情况下,`assert` 失败的时候,会throw一个error, 测试框架会捕获该error,来判断测试失败。
但是,Promise的情况下 `.then` 绑定的函数执行时发生的error 会被Promise捕获,而测试框架则对此error将会一无所知。
我们来改善一下[`assert` 失败的promise测试](http://liubin.github.io/promises-book/#promise-assert-fail), 让它能正确处理 `assert` 失败时的测试结果。
测试正常失败的示例
~~~
it("should use `done` for test?", function (done) {
var promise = Promise.resolve();
promise.then(function (value) {
assert(false);
}).then(done, done);
});
~~~
在上面测试正常失败的示例中,为了确保 `done` 一定会被调用, 我们在最后添加了 `.then(done, done);` 语句。
`assert` 测试通过(成功)时会调用 `done()` ,而 `assert` 失败时则调用 `done(error)` 。
这样,我们就编写出了和 [回调函数风格的测试](http://liubin.github.io/promises-book/#callback-style-test) 相同的Promise测试。
但是,为了处理 `assert` 失败的情况,我们需要额外添加 `.then(done, done);` 的代码。 这就要求我们在编写Promise测试时要格外小心,忘了加上上面语句的话,很可能就会写出一个永远不会返回直到超时的测试代码。
在下一节,让我们接着学习一下最初提到的使用Mocha理由中的支持"Promises测试"究竟是一种什么机制。
- 前言
- 第一章 - 什么是Promise
- 1.1. 什么是Promise
- 1.2. Promise简介
- 1.3. 编写Promise代码
- 第二章 - 实战Promise
- 2.1. Promise.resolve
- 2.2. Promise.reject
- 2.3. 专栏: Promise只能进行异步操作?
- 2.4. Promise#then
- 2.5. Promise#catch
- 2.6. 专栏: 每次调用then都会返回一个新创建的promise对象
- 2.7. Promise和数组
- 2.8. Promise.all
- 2.9. Promise.race
- 2.10. then or catch?
- 第三章 - Promise测试
- 3.1. 基本测试
- 3.2. Mocha对Promise的支持
- 3.3. 编写可控测试(controllable tests)
- 第四章 - Advanced
- 4.1. Promise的实现类库(Library)
- 4.2. Promise.resolve和Thenable
- 4.3. 使用reject而不是throw
- 4.4. Deferred和Promise
- 4.5. 使用Promise.race和delay取消XHR请求
- 4.6. 什么是 Promise.prototype.done ?
- 4.7. Promise和方法链(method chain)
- 4.8. 使用Promise进行顺序(sequence)处理
- 第五章 - Promises API Reference
- 5.1. Promise#then
- 5.2. Promise#catch
- 5.3. Promise.resolve
- 5.4. Promise.reject
- 5.5. Promise.all
- 5.6. Promise.race
- 第六章 - 用語集
- 第七章 - 参考网站
- 第八章 - 关于作者
- 第九章 - 关于译者