進行測試是很重要的。測試能讓我們不費勁地擴充套件和重構我們的程式碼。許多開發者遵循測試驅動的開發流程。我相信寫測試能讓軟體開發變得更有趣,並且通常會帶來更好的程式碼。良好設計以及經過測試的系統更容易維護。
在過去的幾年裡,開發者開始把許多的應用邏輯放到瀏覽器中,我們也開始寫越來越多的JavaScript程式碼。因為這種語言非常流行,開發者們開始建立用於改善JavaScript開發體驗的工具。在這篇文章中,我們將談論一些專門用於測試客戶端JavaScript程式碼的工具。
測試設定
我們來討論一下能夠進行測試的工具型別,它們能讓我們構建、分組以及執行我們的測試。
測試框架
框架包含一些函式如suite、describe、test 或 it。這些能讓我們建立測試的分組,這些分組經常被稱為套件(suit)。例如:
1 2 3 4 5 6 7 8 |
describe('Testing user management', function () { it('should register a new user', function(done) { // the actual testing goes here }); it('should remove a user', function(done) { // the actual testing goes here }); }); |
我們把應用邏輯分割成塊,每個塊都有自己的套件。該套件包括我們想在程式碼上執行的相關測試。流行的JavaScript測試框架有QUnit、Jasmine 或Mocha.
宣告庫
我們用宣告庫來做實際的檢查。它們提供了易用的函式,如下面的例子:
1 |
expect(5).to.be.a('number'); |
有很多的模組可供我們使用。Node.js甚至就有一個內建的模組,也有一些開源的工具供我們選擇,如Chai、Expect 或 should.js。
應該提醒的是,一些測試框架擁有自己的斷言庫。
執行器
我們可以需要或者也可以不需要一個執行器(runner)。有些情況下單一的測試框架不能滿足,因而我們需要在一個特定的上下文來執行測試。為了完成這件事,我們使用一個執行器。有些情況下這些工具被稱為“spec runners”或“test runners.”。這些工具包裝了我們的測試套件,並且在一個特殊的環境下執行。我們將會講到這一點。
應用程式
我們需要一個待測試的應用程式。儘管這只是用於舉例說明,但它不能太過簡單。TODOMVC 看起來是個不錯的選擇。它基本上跟其他的TODO app一樣,使用了許多不同的框架。我們用Backbone.js 的變種。這就是該應用程式的樣子:
假設這是我們上個月在做的一個專案,並且計劃下週釋出。我們想確保它通過一些測試,也假設後端的已經測試過了。唯一的問題是客戶端的JavaScript程式碼。在這個時候,由於應用程式已經完成了,我們最感興趣的是它是否能正常地工作。它是一個TODO app,因此我們需要保證使用者能夠新增、刪除以及編輯任務。
在瀏覽器中測試
我們需要對瀏覽器中執行的程式碼執行檢查,因此在瀏覽器中進行測試是很合理的。我們將使用Mocha來作為框架。由於該框架不帶斷言庫,我們將在專案中引用Chai。我們從todomvc.com 下載了app,並且瀏覽了檔案:
1 2 3 4 5 6 7 8 9 10 |
├── bower_components ├── js │ ├── collections │ ├── models │ ├── routers │ ├── views │ └── app.js └── bower.json └── index.html └── readme.md |
這篇文章是關於測試的,因此我們不打算深入Backbone.js工作原理的細節。然而,這裡介紹一下檔案和目錄的基本細節:
- bower_components – 包含Backbone.js庫、本地儲存助手、jQuery、Underscore.js以及TODOMVC通用檔案
- js – 這個目錄包含這個app的實際程式碼
- bower.json – 定義專案的依賴
- index.html – 包含HTML標籤(模板)
在平常的開發流程中,我們開啟一個瀏覽器、載入應用程式並且使用UI。我們在輸入框敲入了一些文字新建了一個TODO,按Enter鍵然後任務顯示在下面。通過點選小小的X標誌來移除記錄,通過雙擊TODO來編輯任務。我們有很多涉及不同滑鼠事件的動作。
為了測試app,我們不想一遍遍重複上面的步驟。自動化測試可以幫到我們。我們將有效地執行這個應用程式,並且寫能夠與頁面互動就像我們手動操作一樣的程式碼。讓我們建立一個tests_mocha資料夾存放我們的測試。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
├── bower_components ├── js │ ├── collections │ ├── models │ ├── routers │ ├── views │ └── app.js ├── tests_mocha │ ├── package.json │ ├── spec.js │ └── TestRunner.html └── bower.json └── index.html └── readme.md |
Mocha和Chai都可以通過npm來安裝,npm來自Node.js。我們只需把它們新增到package.json檔案,並且在同一個目錄下執行npm install。
1 2 3 4 5 6 7 8 9 |
// package.json { "name": "project", "version": "0.0.1", "devDependencies": { "chai": "1.10.0", "mocha": "2.1.0" } } |
建立測試執行器
spec.js會包含我們的測試,TestRunner.html 是我們將要修改的副本。我們需要讓應用程式跑起來,因此肯定會用到index.html的程式碼。在討論改變之前先看一看原始檔案是什麼樣的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
<!doctype html> <html lang="en" data-framework="backbonejs"> <head> <meta charset="utf-8"> <title>Backbone.js • TodoMVC</title> <link rel="stylesheet" href="bower_components/todomvc-common/base.css"> </head> <body> <section id="todoapp"> ... the base markup of the application </section> <footer id="info"> ... the markup of the footer </footer> <script type="text/template" id="item-template"> ... </script> <script type="text/template" id="stats-template"> ... </script> <script src="bower_components/todomvc-common/base.js"></script> <script src="bower_components/jquery/dist/jquery.js"></script> <script src="bower_components/underscore/underscore.js"></script> <script src="bower_components/backbone/backbone.js"></script> <script src="bower_components/backbone.localStorage/backbone.localStorage.js"></script> <script src="js/models/todo.js"></script> <script src="js/collections/todos.js"></script> <script src="js/views/todo-view.js"></script> <script src="js/views/app-view.js"></script> <script src="js/routers/router.js"></script> <script src="js/app.js"></script> </body> </html> |
客戶端的app會變得相當複雜,我們的一個app需要跑幾個程式。檔案末尾所有的<script>標籤需要包好代表模板的<script>標籤。<section> 也很重要,因此也保留它。
為了看測試的結果需要新增Mocha的樣式,我們只測試JavaScript。因此TODOMVC的base.css可以移除掉,替換頭部中的<link>標籤:
1 |
<link rel="stylesheet" href="./node_modules/mocha/mocha.css"> |
樣式去掉了但是標記仍然在那裡。然而,我們不想讓它可視,因此我們新增另外的CSS類來隱藏它:
1 2 3 4 5 |
<style type="text/css"> #todoapp, #info { display: none; } </style> |
有了這兩處變化,我們仍然可以讓專案執行和工作,但它的介面是不可見的。我們有一個空的頁面來等待我們的測試。下面的程式碼在頁面的底部執行,就在TODOMVC的指令碼之後:
1 2 3 4 5 6 7 8 9 10 11 12 |
<div id="mocha"></div> <script src="./node_modules/mocha/mocha.js"></script> <script src="./node_modules/chai/chai.js"></script> <script> mocha.ui('bdd'); mocha.reporter('html'); var expect = chai.expect; </script> <script src="./spec.js"></script> <script> mocha.run(); </script> |
空的<div>被模板用來顯示結果,在那之後我們新增Mocha和Chai。最後,我們執行測試。注意,我們的spec.js是在測試框架和宣告庫被初始化時在mocha.run()之前新增的。實際上,瀏覽器會:
- 匯入Mocha的CSS;
- 匯入TODOMVC的檔案並且執行應用程式;
- 匯入Mocha和Chai;
- 匯入我們的spec.js;
- 執行測試
編寫測試
準備就緒,讓我們開始寫測試。之前我們提到過要檢查三件事情:使用者能否新增、刪除、編輯待完成任務。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// spec.js describe("Testing TODOMVC", function () { var setText = function(text, selector) { var input = $(selector || '#new-todo'); var e = $.Event("keypress"); e.which = e.keyCode = 13; return input.val(text).trigger(e); }; before(function() { window.localStorage.removeItem('todos-backbone', ''); app.todos.reset(); }); it("Adding new TODOs", function () { setText('TODO A'); setText('TODO B'); expect($('#todo-list li').length).to.be.equal(2); }); it("Deleting TODO", function () { $('#todo-list li:first-child .destroy').click(); expect($('#todo-list li').length).to.be.equal(1); }); it("Edit and add TODOs", function () { setText('A new TODO'); $('#todo-list li:first-child').addClass('editing'); setText('A new TODO', '#todo-list li:first-child .edit').blur(); expect($('#todo-list li').length).to.be.equal(2); expect($('#todo-list li label').eq(0).text()).to.be.equal($('#todo-list li label').eq(1).text()) }); }); |
測試從呼叫describe 函式開始,把我們的檢查放在一個測試套件裡。setText 函式是用來改變輸入框的值並模擬按下Enter 鍵。
大多數測試框架允許我們在測試執行之前執行邏輯,這就是我們用before 函式的原因。在本例中,我們需要清空儲存在localStorage 中的資料,因為之後我們期待看到列表中待完成任務的具體數目。
接下來的it 呼叫表示新增、刪除、編輯的三種操作。注意我們用的$ (jQuery)和expect 都是全域性函式。
執行測試
完成這段程式碼,就可以用我們最喜歡的瀏覽器開啟TestRunner.html,並且結果顯示如下:
我們現在能保證我們的專案提供了所需的功能。我們有一個測試並且它是有點自動化的。之所以說“有點”是因為測試在瀏覽器中執行,並且我們仍然需要手工開啟TestRunner.html。
這就是使用這種的問題之一。我們不能強迫開發者一直在瀏覽器中執行測試。測試過程應該是配置或提交過程的一部分。為了達到這個目標,我們需要將測試移到終端。
使用PhantomJS進行測試
下面我們要解決的一個問題是,找到一個能在終端執行的瀏覽器。我們需要一個瀏覽器,因為Backbone.js需要渲染UI並且我們要跟它互動。有一種被稱為沒有介面的(headless) 特殊的瀏覽器,它並沒有一個視覺化介面。
我們通過程式碼來控制它。但是,它們跟真實的瀏覽器功能一模一樣。最流行的一款是PhantomJS。嘗試一下看它怎樣處理我們的測試。
PhantomJS以可執行檔案的形式釋出。換句話說,當成功安裝之後我們有一個命令變數phantomjs 。它適用於幾乎每一個作業系統。同該瀏覽器一同使用,我們將使用Node.js和它的npm。
在終端執行測試
假設我們已經安裝好了PhantomJS,下一步是在終端執行我們的Mocha測試。實際過程中,我們需要在瀏覽器中載入TestRunner.html,檢查來自Mocha框架的結果。我們可以手動操作。但是為了節省時間,我們使用Node.js中的mocha-phantomjs 模組。
快速執行npm install -g mocha-phantomjs會讓mocha-phantomjs可在控制檯中使用。直接將tests_mocha檔案複製到新的目錄tests_mocha-phantomjs下。我們要做的唯一的變動就是將
1 2 3 |
<script> mocha.run(); </script> |
變為:
1 2 3 4 |
<script> if (window.mochaPhantomJS) { mochaPhantomJS.run(); } else { mocha.run(); } </script> |
模組從測試框架獲得回應,並將它傳送到終端。這就是結果應該有的樣子:
現在我們的檢查在終端裡執行,我們能新增mocha-phantomjs呼叫到我們的持續整合設定。
PhantomJS很好,但是它在單一的瀏覽器中執行我們的程式碼。如果我們在不同的瀏覽器中測試程式碼呢?特別是針對客戶端的JavaScript,我們應該保證我們的應用程式能在不同的環境中工作。並且不止如此,我們想在真實的瀏覽器中測試。Karma 專案能提供這個功能。
使用Karma作為測試執行器
與mocha-phantomjs類似,Karma 以Node.js模組的形式釋出。但是,這一次我們不僅需要一個模組,還需要其它幾個模組。因此,讓我們按照上述的想法,將tests_mocha拷貝到新的檔案tests_karma裡。package.json檔案應當是這個樣子:
1 2 3 4 5 6 7 8 9 10 11 |
{ "name": "project", "version": "0.0.1", "devDependencies": { "karma": "https://github.com/krasimir/karma/tarball/589f55a8abab613ec915a871ee976ca0e15ad36f", "karma-mocha": "^0.1.10", "karma-phantomjs-launcher": "^0.1.4", "karma-chrome-launcher": "0.1.7", "karma-chai": "0.1.0" } } |
除了上面的包,我們還需要karma-cli。在執行npm install(這會安裝上面列出的依賴)之後再執行npm install -g karma-cli。 karma-cli 有karma 命令,我們可以呼叫它來在終端執行測試執行器。
使用KARMA的問題
我在過去幾個月看了很多有關Karma的東西,並且真的想嘗試它。但是,我發現它被設計專門用於單元測試,而不是整合測試。
執行器的命令列工具接受JSON物件格式的配置,有一些選項,但是沒有一個接受HTML檔案。我們可以傳送JavaScript檔案到瀏覽器,但是我們不能定義要載入的HTML。
有一個Karma使用的上下文模板,它的所有功能是注入JavaScript程式碼和測試。為了使用方便,這是不夠的。我們有HTML標記及<script>中的模板。在執行應用程式之前它們應該已經被載入到頁面中了。
解決方案
我所做的是fork這個專案,並且在配置中增加了一個選項。這可以讓我們設定上下文模板,這也是我為什麼在package.json 檔案中新增一個URL。
保持spec.js不變,把TestRunner.html變為:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<!DOCTYPE html> <html> <head> <title></title> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> </head> <body> <section id="todoapp"> ... </section> <footer id="info"> ... </footer> <script type="text/template" id="item-template"> ... </script> <script type="text/template" id="stats-template"> ... </script> <script type="text/javascript"> if (window.opener) { window.opener.karma.setupContext(window); } else { window.parent.karma.setupContext(window); } %MAPPINGS% </script> %SCRIPTS% <script type="text/javascript"> window.__karma__.loaded(); </script> </body> </html> |
需要的<section>和 <footer>都包含在模板中了,最後的程式碼是Karma用於構建最終文件及執行測試。
配置
我提到框架使用了一個配置檔案。使用下面的內容建立一個tests_karma/karma.conf.js檔案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
// karma.conf.js module.exports = function(config) { config.set({ basePath: '', client: { contextFile: '/TestRunner.html' }, frameworks: ['mocha', 'chai'], files: [ '../bower_components/todomvc-common/base.js', '../bower_components/jquery/dist/jquery.js', '../bower_components/underscore/underscore.js', '../bower_components/backbone/backbone.js', '../bower_components/backbone.localStorage/backbone.localStorage.js', '../js/models/todo.js', '../js/collections/todos.js', '../js/views/todo-view.js', '../js/views/app-view.js', '../js/routers/router.js', '../js/app.js', 'spec.js' ], exclude: [ ], preprocessors: { }, reporters: ['progress'], port: 9876, colors: true, logLevel: config.LOG_INFO, autoWatch: false, browsers: ['PhantomJS', 'Chrome'], singleRun: false }); }; |
在這個配置裡,我們列出了要注入到頁面的JavaScript檔案,contextFile 設定是我之前討論過的變化。注意,我們有兩種瀏覽器來執行測試。
執行KARMA
最後一步是在終端執行karma start ./karma.conf.js –single-run。結果如下:
在這一部分的開頭karma-phantomjs-launcher和karma-chrome-launcher。該框架使用兩個模組來執行我們指定的瀏覽器。
因此,我們嘗試在瀏覽器中執行測試,但是這個方法不能擴充套件。我們通過mocha-phantomjs讓其在終端執行,但是那意味只在一個瀏覽器中測試。第三種嘗試是使用Karma作為執行器,開啟兩個不同的瀏覽器,其中一個不是沒有介面的(headless)瀏覽器。最後一個步驟有點複雜,包括一些模組及一個框架補丁。讓我們嘗試另一個執行器——DalekJS。
使用DalekJS測試
DalekJS使用一種不同的方法,它不需要測試框架或者斷言,已經自帶了。
安裝非常簡單。我們再一次需要Node.js和npm ,因為這個工具是以Node.js的包釋出的。跟Karma一樣,我們也需要命令列客戶端,以及DalekJS框架本身。
1 2 |
// after this line we will have `dalek` command available npm install dalek-cli -g |
我們建立另一個tests_dalekjs 資料夾,包含package.json 檔案:
1 2 3 4 5 6 7 |
{ "name": "project", "version": "0.0.1", "dependencies": { "dalekjs": "0.0.9" } } |
當我們安裝好了兩個模組,就可以進行測試了。
編寫測試
好訊息是我們不需要接觸HTML,只需把index.html的檔案路徑拷貝到tests_dalekjs/TestRunner.html檔案中,剩下的步驟都一樣。
因為DalekJS有自己的語法,我們不能像上面的測試使用spec.js檔案。下面是使用DalekJS API所寫的三種操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
var setText = function(text, selector) { var input = $(selector || '#new-todo'); var e = $.Event("keypress"); e.which = e.keyCode = 13; input.val(text).trigger(e); }; module.exports = { 'Testing TODOMVC app': function (test) { test .open('TestRunner.html') .execute(setText, 'TODO A') .execute(setText, 'TODO B') .assert.numberOfElements('#todo-list li', 2, 'Should have two TODOs') .execute(function() { $('#todo-list li:first-child .destroy').click(); }) .assert.numberOfElements('#todo-list li', 1, 'Should have two TODOs') .execute(setText, 'A new TODO') .execute(function() { $('#todo-list li:first-child').addClass('editing'); $('#todo-list li:first-child .edit').val('A new TODO').blur(); }) .assert.numberOfElements('#todo-list li', 2, 'Should have two TODOs') .assert.text('#todo-list li:first-child label').is('A new TODO') .assert.text('#todo-list li:second-child label').is('A new TODO') .done(); } }; |
再一次,我們有一個幫助的方法來設定輸入域的值,並且觸發Enter 按鈕。我們匯出的物件包含TODO的新增、刪除、編輯。像這樣設計API是很友好的,因為我們僅通過看方法的執行來知道正在發生什麼。
有一個比較麻煩的方法是執行。它接受一個在瀏覽器上下文下執行的函式。
執行測試
我們使用dalek ./tests_dalekjs/spec.js執行測試,結果:
我們應該記住,DalekJS跟Karma一樣,能夠在Chrome、IE、Firefox 和 Safari下執行。相當多的現代瀏覽器是支援的,我們所要做的是安裝額外的模組,如 dalek-browser-chrome。更多有關支援的瀏覽器,點這裡。
Atomus——測試的另一種工具
Atomus 是我工作時使用的工具,上面所有的功能選項都很棒。它們中的大多數經過了大型社群的良好測試。然而,在我看來,它們並非是理想的。
我們能覆蓋使用者的全部過程是很好的,但是通常情況下我們只需要測試應用程式的某一個部分。如果我們只想測試Backbone.js應用的特定檢視呢?使用DalekJS這是很困難的,使用Karma可行但是有點麻煩。模組mocha_phantomjs跟工作方案很接近但是也有一些侷限。
當我們進行單元測試時,我們意識到我們所做的是DOM模擬。在大多數情形下我們對UI不感興趣,而對它的行為感興趣。此時我們找到了jsdom,它是WHATWG和HTML標準的Javascript的實現。
我們建立了一些測試,發現它工作得非常好。它支援DOM操作和DOM事件排程/監聽。甚至支援Ajax請求。Atomus是jadom的包裝器,提供一個強健和友好的API。
建立測試
讓我們以使用Atomus進行的TODOMVC測試來結束這篇文章。我們再一次用到Mocha 和Chai。在新目錄tests_atomus建立package.json,定義依賴:
1 2 3 4 5 6 7 8 9 |
{ "name": "project", "version": "0.0.1", "devDependencies": { "chai": "1.10.0", "mocha": "2.1.0", "atomus": "0.1.12" } } |
TestRunner.html跟原始的index.html檔案一樣——唯一引入的外部JS檔案應該移除掉,因為spec,js 中已經引入過了。檔案以下面的程式碼開始:
1 2 3 4 5 6 7 8 9 10 |
var fs = require('fs'); var expect = require('chai').expect; describe("Testing TODOMVC", function () { var atomus = require('atomus'); var htmlStr = fs.readFileSync('./TestRunner.html').toString('utf8'); var browser, $; }); |
我們使用檔案系統API來讀取TestRunner.html的內容。browser 變數代表Atomus API。Atomus庫會自動注入jQuery,因此$可以作為快捷符號。第一個測試是這樣:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
it("Adding new TODOs", function (done) { browser = atomus() .external(__dirname + '/../bower_components/todomvc-common/base.js') .external(__dirname + '/../bower_components/jquery/dist/jquery.js') .external(__dirname + '/../bower_components/underscore/underscore.js') .external(__dirname + '/../bower_components/backbone/backbone.js') .external(__dirname + '/../bower_components/backbone.localStorage/backbone.localStorage.js') .external(__dirname + '/../js/models/todo.js') .external(__dirname + '/../js/collections/todos.js') .external(__dirname + '/../js/views/todo-view.js') .external(__dirname + '/../js/views/app-view.js') .external(__dirname + '/../js/routers/router.js') .external(__dirname + '/../js/app.js') .html(htmlStr) .ready(function(errors, window) { $ = window.$; browser.keypressed($('#new-todo').val('TODO A'), 13); browser.keypressed($('#new-todo').val('TODO B'), 13); expect(window.$('#todo-list li').length).to.be.equal(2); done(); }); }); |
我們在這裡初始化虛擬瀏覽器、定義外部的js檔案、設定HTML標記的頁面。ready函式接收一個回撥,但頁面和資源全部被載入完成之後會觸發。我們接收一個window物件,跟實際瀏覽器中的window物件一樣。我們可以認為變數是指向瀏覽器的API的,當然也是指向全域性作用域的。
Atomus有一個keypressed 和clicked 的方法模擬使用者互動。我們也可以使用流行的jQuery方法來獲得同樣的結果,但是這些內建的方法可能會帶來一些bugs。
既然我們有了browser 變數,我們能繼續刪除和編輯TODO了。
1 2 3 4 5 6 7 8 9 10 11 12 |
it("Deleting TODO", function () { $('#todo-list li:first-child .destroy').click(); expect($('#todo-list li').length).to.be.equal(1); }); it("Edit and add TODOs", function () { browser.keypressed($('#new-todo').val('A new TODO'), 13); $('#todo-list li:first-child').addClass('editing'); $('#todo-list li:first-child .edit').val('A new TODO').blur(); expect($('#todo-list li').length).to.be.equal(2); expect($('#todo-list li label').eq(0).text()).to.be.equal($('#todo-list li label').eq(1).text()) }); |
執行測試
為了執行測試我們不需要命令列客戶端,只需要鍵入mocha ./spec.js ,結果是:
注意,當我們使用Atomus時主要的事情不是執行器或者沒有介面的瀏覽器——它是測試框架。就是它在驅動測試,Atomus只是一個幫助工具。
在我們的案例中,它幫助我們覆蓋不同層次的客戶端架構測試。我們有簡單UI元素的測試,同時使用同樣的工具來整合測試。
為了完成一些有趣的事情,我們看下面的程式碼:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
var mockups = [ { url: '/api/method/action', method: 'GET', response: { status: 200, responseText: JSON.stringify({"id": "AAA"}) } } ]; var atomus = require('../lib'); var b = atomus() .ready(function(errors, window) { b.addXHRMock(mockups); var $ = window.$; $.ajax({ url: '/api/method/action' }).done(function(result) { console.log(result.id); // AAA }); }); |
在複雜的環境中,當應用程式的UI跟後端有通訊時,我們需要模擬HTTP請求。在我們的案例中,我們想要涵蓋一個完整的使用過程,但是這實際上變得很複雜,因為我們想要進行單獨的測試。因此,我們模擬傳統的XMLHttpRequest 物件,現在開發者可以通過不同的響應連結到URL了。
結論
測試是很有趣的——特別是當我們有這麼多的工具可供使用的時候。不管我們有著哪種型別的應用,我們應該明確的是有一種測試它的方法。我希望這篇文章能夠幫助你找到合適你的專案的正確工具。