Ajax單元測試傻瓜教程

原文出處 :AJAX單元測試傻瓜教程css

Ajax 請求常常容易發生錯誤,客戶端發送的數據出問題,服務器端返回的數據有誤都會致使 Ajax 請求錯誤。你不能保證與服務器的鏈接老是工做正常。Ajax請求須要將用戶的輸入發送給服務器並返回服務器響應,所以,對於數據的正確處理相當重要。
可是因爲Ajax是異步的,測試它的同時必須保證獨立性,咱們如何才能在Ajax與服務器進行通訊的時候對其進行單元測試呢?
不要怕,讓咱們看一看接下來的例子,學習一下如何對Ajax請求進行單元測試。html

設置

在咱們開始單元測試以前,咱們須要安裝幾個必須的工具。node

  • 新建一個目錄,用來存放必要的文件npm

  • 使用 npm install mocha chai sinon 安裝 Mocha, Chai, Sinonjson

測試運行器

爲了使事情簡單,咱們將直接在瀏覽器中運行測試。若是你更喜歡基於命令行的測試的話,測試運行的結果也將會和瀏覽器中的結果徹底一致。
咱們將會使用如下的文件做爲測試運行器。我將其命名爲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請求

咱們的示例模塊中有一個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
});

beforeEachafterEach就像他們的名字同樣,將會在每一次的測試前和測試後被調用。在每個測試以前,咱們實例化了一個 fake XMLHttpRequest 而且將每個被建立的 fake request 放入了一個數組中,這些值被存儲在this.xhrthis.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();
});

由於以前咱們建立了datadataJson變量來表明傳遞的數據,因此若是響應正確,響應的數據應該被解析成一個對象。
如今,咱們能夠在瀏覽器中運行咱們的測試了,打開test.html文件,你應該能夠看到關於測試經過的信息。

測試POST請求

在咱們的示例中還有一個向服務器發送數據的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 的官網瞭解。

相關文章
相關標籤/搜索