原文出处 :AJAX单元测试傻瓜教程css
Ajax 请求常常容易发生错误,客户端发送的数据出问题,服务器端返回的数据有误都会致使 Ajax 请求错误。你不能保证与服务器的链接老是工做正常。Ajax请求须要将用户的输入发送给服务器并返回服务器响应,所以,对于数据的正确处理相当重要。
可是因为Ajax是异步的,测试它的同时必须保证独立性,咱们如何才能在Ajax与服务器进行通讯的时候对其进行单元测试呢?
不要怕,让咱们看一看接下来的例子,学习一下如何对Ajax请求进行单元测试。html
在咱们开始单元测试以前,咱们须要安装几个必须的工具。node
新建一个目录,用来存放必要的文件npm
使用 npm install mocha chai sinon
安装 Mocha
, Chai
, Sinon
json
为了使事情简单,咱们将直接在浏览器中运行测试。若是你更喜欢基于命令行的测试的话,测试运行的结果也将会和浏览器中的结果彻底一致。
咱们将会使用如下的文件做为测试运行器。我将其命名为test.html
。数组
<!DOCTYPE html> <html> <head> <title>Mocha Tests</title> <link rel="stylesheet" href="node_modules/mocha/mocha.css"> </head> <body> <div id="mocha"></div> <script src="node_modules/mocha/mocha.js"></script> <script src="node_modules/sinon/pkg/sinon-1.12.2.js"></script> <script src="node_modules/chai/chai.js"></script> <script>mocha.setup('bdd')</script> <script src="testApi.js"></script> <script src="test.js"></script> <script> mocha.run(); </script> </body> </html>
注意mocha.js
,mocha.css
,sinon-1.17.1.js
,chai.js
的文件路径。由于我是用npm
安装它们的,因此它们都在node_modules
目录下。对于 Sinon
,你可能须要更改文件名来匹配安装的版本,我在这里使用的是版本是1.17.1。同时也注意testApi.js
,test.js
这两个文件,这两个文件做为个人实例模块和测试用例,我将会在接下来逐一介绍它们。浏览器
接下来,咱们将建立一个基础的模块,该模块将会发送一些Ajax请求。咱们将用它来向大家展现如何对Ajax进行单元测试。
咱们将该文件命名为testApi.js
。服务器
var testApi = { get: function(callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', 'http://jsonplaceholder.typicode.com/posts/1', true); xhr.onreadystatechange = function() { if(xhr.readyState == 4) { if(xhr.status == 200) { callback(null, JSON.parse(xhr.responseText)); } else { callback(xhr.status); } } }; xhr.send(); }, post: function(data, callback) { var xhr = new XMLHttpRequest(); xhr.open('POST', 'http://jsonplaceholder.typicode.com/posts', true); xhr.onreadystatechange = function() { if(xhr.readyState == 4) { callback(); } }; xhr.send(JSON.stringify(data)); } };
这段代码开起来应该很熟悉,咱们写了两个函数,一个函数中使用GET
方法获取数据,另外一个函数中使用POST
方法向服务器发送数据,这些都是最普通的 Ajax请求。咱们在这里使用了JSONPlaceholder API,它是一个免费的在线REST服务,你可使用它提供的模拟数据,很是适合快速测试。网络
以后咱们须要建立一个框架,在里面添加每一个情景的测试集。该文件被命名为test.js
。框架
chai.should(); describe('TestAPI', function() { //Tests etc. go here });
Mocha
中使用describe
来建立一个测试用例,该测试用例即是咱们添加测试代码的地方。chai.should()
将容许咱们使用 "should style" 断言。这意味着咱们能够轻松的验证咱们的测试结果,如:someValue.should.equal(12345)
。
咱们的示例模块中有一个get
函数,该函数能够被用来加载服务器传送过来的数据。咱们将会建立一个测试函数来证实由服务器取到数据是一个JSON数据。可是该GET
请求是由XMLHttpRequest
发出的,因为咱们测试的时候并无服务器接收咱们的数据,因此咱们不能真的发出一个 Http 请求,那么咱们如何才能避免真的发出请求呢?又如何能获得返回的数据呢?
别着急,这个时候就到了 Sinon 出场了。咱们一开始在就在test.html
中引用了 Sinon 的库,有了 Sinon,咱们就能够模拟服务器响应。咱们能够将XMLHttpRequest用一个替身来代替,咱们称之为 fake XMLHttpRequest,这样咱们就能在测试中轻松控制Ajax请求了。
咱们须要稍微更新一下咱们的测试用例框架,如下是更改以后的test.js
文件。
chai.should(); describe('TestAPI', function() { beforeEach(function() { this.xhr = sinon.useFakeXMLHttpRequest(); this.requests = []; this.xhr.onCreate = function(xhr) { this.requests.push(xhr); }.bind(this); }); afterEach(function() { this.xhr.restore(); }); //Tests etc. go here });
beforeEach
和afterEach
就像他们的名字同样,将会在每一次的测试前和测试后被调用。在每个测试以前,咱们实例化了一个 fake XMLHttpRequest 而且将每个被建立的 fake request 放入了一个数组中,这些值被存储在this.xhr
和this.request
中,这样咱们就能够在该测试中的其余函数中使用了。
在每一次测试以后,咱们使用了this.xhr.restore
来恢复初始的XMLHttpRequest对象。
如今,咱们能够开始在test.js
中写下咱们的第一个测试集:
it('should parse fetched data as JSON', function(done) { var data = { foo: 'bar' }; var dataJson = JSON.stringify(data); testApi.get(function(err, result) { result.should.deep.equal(data); done(); }); this.requests[0].respond(200, { 'Content-Type': 'text/json' }, dataJson); });
咱们定义了一个对象data
和它的JSON版本dataJson
做为咱们将要传递的数据。下一步,咱们调用了testApi.call
,在它的回掉函数中咱们使用了result.should.deep.equal
来验证结果是否是与咱们所指望的数据一致。咱们还调用了done()
,它的做用是告诉 Mocha 该异步测试完成了。在这里,要注意done
是测试函数中的一个参数。
最后,咱们调用了this.requests[0].respond
。你还记得以前的beforeEach
函数么?它在每一次的测试开始以前,将全部的 fake XMLHttpRquest 放入了this.requests
中。当咱们的测试调用testApi.get
时,它建立了一个请求。这个请求被存入了this.requests
这个数组中,this.requests[0]
就表明了这个请求。
一般来讲,XMLHttpRequest 没有respond
函数,这里的respond
用来响应一个 fake request。咱们在该响应中设置状态码为200
,意思是成功响应。同时,咱们将响应头中的Content-Type
设置为text/json
,这是由于咱们传递的是 JSON 数据。respond
函数中的最后一个参数表示响应体,咱们将其设置为以前建立好的dataJson
变量。
fake XMLHttpRequest 模拟了一个 GET 请求的响应,在获得响应以后,testApi.get
中的回掉函数将会被调用。该回调函数中,咱们将响应中获得的结果与data
变量作对比:
testApi.get(function(err, result) { result.should.deep.equal(data); done(); });
由于以前咱们建立了data
和dataJson
变量来表明传递的数据,因此若是响应正确,响应的数据应该被解析成一个对象。
如今,咱们能够在浏览器中运行咱们的测试了,打开test.html
文件,你应该能够看到关于测试经过的信息。
在咱们的示例中还有一个向服务器发送数据的post
函数,发送的数据是 JSON 格式的。接下来咱们就要完成对该函数的测试。
it('should send given data as JSON body', function() { var data = { hello: 'world' }; var dataJson = JSON.stringify(data); testApi.post(data, function() { }); this.requests[0].requestBody.should.equal(dataJson); });
就和以前同样,咱们首先定义了一个测试数据data
和它的 JSON 格式的变量dataJson
。以后咱们调用了testApi.post
。与以前测试 GET 请求不同的地方是,这一次咱们只须要验证要被发送的数据是否被正确的转换成了 JSON 格式,由于咱们只须要保证 POST 请求中发出的数据是正确的,所以咱们的回掉函数是空的。
该段代码中最后一行使用了一个断言来肯定发送数据的正确性。与以前同样,咱们使用了 fake XMLHttpRequest,可是这一次咱们要证实它携带了正确的数据。POST 请求中携带的数据存放在 fake XMLHttpRequest 的 requestBody
属性中,咱们将其与dataJson
做比较来验证咱们的行为。
做为最后一个示例,让咱们来是测试一个失败的请求。由于网络链接中可能出现不少问题,同时服务器也可能出现问题,而且咱们不该该让咱们网站的用户对具体的错误信息感到疑惑,因此错误测试很是重要。
示例模块中的回调函数中有两个参数,第一个参数就是错误信息,第二个参数则是每一次 Http 请求响应获得的结果。代码以下:
it('should return error into callback', function(done) { testApi.get(function(err, result) { err.should.exist; done(); }); this.requests[0].respond(500); });
因为是错误测试,因此这一次咱们不须要任何数据。咱们调用了testApi.get
,并在其回掉函数中来验证 error 参数的存在。为了模拟响应错误,最后一行中的 fake XMLHttpRequest 发送了一个内部服务器错误的状态码 500 来触发错误处理程序。
Ajax请求的测试是很重要的,若是你能证实每一次请求都是正确的,那么你应用程序中的其余部分就能彻底相信每一次 Ajax 请求获得的数据。假如你正在使用 JQuery Ajax,测试的方法与例子的方法是如出一辙的。你一样可使用 Sinon 中的 fake XMLHttpRequests。固然,Sinon 中并不仅有 fake XMLHttpRequest, 它还有 fake Server 用来模拟服务器响应,感兴趣的话能够去 Sinon 的官网了解。