Dojo 敏捷開發:集成 DOH 單元測試到 Ant build
簡介: DOH 是一種基于 Dojo 技術的 JavaScript 單元測試框架,也是目前主流的 Dojo 單元測試技術。Ant 是基于 Java 技術的構建工具,Ant build 是敏捷開發中用于持續集成的主流方法。本文首先介紹 Dojo 單元測試的類型以及使用 DOH 運行單元測試的方式,然后重點介紹如何將 DOH 編寫的 Dojo 單元測試集成到 Ant build 中,能夠讓單元測試的結果展示在 build 結果中,并且進一步影響 build 的成功或者失敗。
熟悉敏捷開發的讀者都知道,在項目開發過程中創建一個定期運行的 build 是至關重要的,它可以幫助項目團隊及時的發現項目中存在的問題以及查看迭代的結果。通常 build 中都會包含一項很重要的工作就是執行項目中的單元測試并匯報單元測試的執行結果,如果有單元測試失敗那么就讓 build 失敗。對于使用 Dojo 開發的項目而言,如何將 Dojo 代碼的單元測試集成到項目的 build 中是貫徹敏捷開發原則必不可少的一步。
本文將首先簡單對 Dojo 單元測試框架 DOH 進行簡單介紹,然后說明如何將編寫的單元測試集成到 Ant build 中。
DOH (Dojo Objective Harness) 是 Dojo 提供的 JavaScript 測試套件,也是當前最有效的 Dojo 代碼單元測試框架。它不僅可以用于測試 Dojo 代碼,也可以獨立于 Dojo ,用于測試其它 JavaScript 代碼。
在一個用 Dojo 開發的應用中,按照代碼的功能通常可將測試點分為如下幾種類型:JavaScript 代碼邏輯、Ajax 異步通信、widget 的顯示及行為、UI Look & Feel。
- JavaScript 代碼邏輯,是指一個功能邏輯相對獨立的 JavaScript 代碼段,通常是一個 JavaScript function 或者一個 Dojo class 的 method。它可以在一個相對封閉的數據集中進行執行,執行的結果是返回一個獨立的數據集或者改變封閉數據集中的數據。對于這種代碼的單元測試是非常容 易編寫和執行的,而且執行時也不會產生任何的副作用。我們只需要構造一個數據集,然后在這個數據集上調用該 JavaScript 代碼段,最后檢驗執行結果是否與預期相符即可。這種單元測試不需要與服務器通信也不需要后端代碼的支持,而且大多不會存在瀏覽器的兼容性問題。
- Ajax 異步通信:在使用 Ajax Framework 進行開發的應用系統中,異步請求服務器數據是非常常見的操作,測試 Ajax 很關鍵的是等待服務器返回結果然后對結果進行判斷,DOH 提供了 DOH.Deffered 對象,利用它可以很方便的進行 Ajax 測試。當然這類測試需要服務器端進行支持,也可以在客戶端用數據文件模擬服務器端返回的數據進行測試。
- Widget 的顯示及行為:Dojo 的 dijit 庫提供了強大的 Widget 支持,同時也提供了開發自定義 Widget 的能力。在應用系統中,所有用戶可見部分的顯示和行為都是通過 Widget 來實現的。對于 Widget 的測試就包括對其在瀏覽器中所展現的樣式以及與用戶交互過程中所展現的行為的測試。由于這些與瀏覽器的實現關系非常密切,所以對 Widget 的測試需要針對不同瀏覽器測試其兼容性問題。
- UI Look & Feel:Look & Feel 對于 UI 系統也是非常重要的一個方面。在 Dojo 應用系統中,這里主要是對自開發的 CSS 樣式表的驗證,檢查頁面在不同的瀏覽器中所展現出來的樣式是否符合要求。但是,據筆者了解,現有的技術方案都不會對這類問題進行單元測試,而是將這類問題 放到功能測試中進行覆蓋。
DOH 作為一種 JavaScript 單元測試框架,它對以上所描述的幾種類型都有很好的支持。它針對不同類型的單元測試提供了不同的測試模式。
編寫好的 DOH 單元測試需要怎么運行呢? DOH 支持兩種運行方式:瀏覽器運行方式和命令行運行方式。
Dojo 提供了統一界面來運行單元測試,那就是 DOH 中的 runner.html,它把大量單獨的單元測試文件(JavaScript 和 HTML 文件)封裝到一個文件中統一管理。瀏覽器運行方式就是指使用瀏覽器訪問該文件來執行單元測試,并以直觀的方式反映運行結果。開發人員可將自己開發的單元測 試樣例加到 runner.html 中進行測試,運行時可以在瀏覽器的頁面上看到執行進度、打印的 log 信息、UI 顯示界面,以及運行結果等等。
優點 :可以很直觀的查看運行的過程和結果,對 UI 頁面和 Widget 測試天然地提供了執行環境的支持。擅長 UI 頁面及 Widget 的顯示和行為的測試,以及 Ajax 異步通信測試。
不足: 測試過程中需要啟動瀏覽器,UI 的可視化測試需要人為判斷是否符合需求,很難自動化。
DOH 還提供了一種不依賴于瀏覽器來運行單元測試的方法,那就是利用命令行的方式。它是通過使用 Dojo util 下面的 JavaScript 執行引擎 – Rhino 來執行單元測試的。運行方式是在 dojo/util/doh 目錄下運行命令:
java -jar ../shrinksafe/js.jar runner.js testModule= ${yourmodule} |
其中 runner.js 是 DOH 提供的一個執行單元測試的 JavaScript 入口點,${yourmodule} 是自定義的測試模塊名稱。
優點:執行過程不需要人為參與,執行結果也可以通過 DOH 的 assert 自動判斷,擅長 JavaScript 邏輯測試,單元測試很容易編寫。
不足:沒有瀏覽器的環境,無法對可視化頁面或 Widget 的顯示效果進行測試,所使用的 Rhino JavaScript 引擎可能與實際使用的瀏覽器中的 JavaScript 引擎有所差異,這可能會導致一些特定代碼的測試結果與實際運行結果不同,無法進行瀏覽器的兼容性測試。
所謂集成 DOH 單元測試到 Ant build 中,就是尋找一種方式將使用 DOH 編寫的單元測試作為 Ant build 的一個 target 進行運行,并且能夠將單元測試結果體現在 build 的運行結果中,當單元測試失敗時能夠使 build 失敗。
在介紹集成方式之前,首先來看一下 Dojo 項目代碼的組織方式,因為組織方式的不同將會影響到 build 中的一些參數配置。
以下所介紹的 Dojo 項目代碼的組織方式只是一種比較流行的組織方式,并不是唯一可行的,您可采用不同的組織方式。本文后面實例中的參數配置將以下面介紹的組織方式為準。
通常一個 Web 項目的所有 Web 資源都包含在一個 WebContent 目錄中,其中包括圖片、JavaScript 腳本、CSS 等。Dojo 項目還包括 Dojo 類庫、項目 Dojo 代碼、項目的 Dojo 單元測試代碼。如下圖展示了這些文件的目錄組織方式:
圖 1. Dojo 項目的目錄組織方式

其中,dojo 目錄是 Dojo 的庫目錄;com 是項目 Dojo 代碼目錄,com 是項目代碼包的頂級目錄;tests 是項目單元測試目錄;css 是項目 CSS 文件所在的目錄;images 是項目圖片文件所在的目錄。這些目錄中與本文所介紹的主題相關的有 dojo 目錄和 tests 目錄。
典型的 Dojo 庫的 dojo 目錄包含子文件夾:dojo、dijit、dojox、util,util 中包含 shrinksafe、doh 等目錄;tests 目錄中通常會定義一個 module.js 文件,用于定義所有待運行的 Dojo 單元測試列表。
DOH 的命令行運行方式通過一個 Java 命令運行 js.jar,并且將 runner.js 和待運行的模塊通過參數傳遞進去。集成這種方式到 Ant build 中是顯而易見的,因為 Ant 直接提供了運行 Java 命令的方式。清單 1 的 Ant 片段就能夠完成運行 Dojo 單元測試的目的(假定 build.xml 文件在 js 目錄中)。
清單 1. 集成命令行運行方式的 Ant 片段
<target name="runUT"> <java jar="dojo/util/shrinksafe/js.jar" fork="true" failonerror="true"> <arg value="dojo/util/doh/runner.js"/> <arg value="dojoUrl=dojo/dojo/dojo.js"/> <arg value="dohBase=dojo/util/doh/"/> <arg value="testUrl=tests/module.js"/> <arg value="testModule=tests.module"/> </java> </target> |
這里的 failonerror 屬性一定要設置為 true,這樣當單元測試失敗時 build 才會失敗。Java 命令里面的 arg 定義了執行 js.jar 時所需要的參數:
- dojo/util/doh/runner.js: 這個參數指定了 DOH 中 runner.js 相對于 build basedir 的路徑;
- dojoUrl=dojo/dojo/dojo.js: 這個參數指定了 dojoUrl 的值,即相對于 build basedir,Dojo 庫中 dojo.js 的路徑;
- dohBase=dojo/util/doh/: 這個參數指定了 dohBase 的值,即相對于 build basedir,DOH 根目錄的相對路徑,即項目目錄中 doh 目錄的路徑;
- testUrl=tests/module.js: 這個參數指定了 testUrl 的值,即相對于 build basedir,待執行單元測試的路徑,通常直接指向 module.js 文件,它是單元測試的入口;
- testModule=tests.module: 這個參數指定了 testModule 的值,即待測試模塊的名稱,通常定義為 module.js 所定義的模塊。
當該 target 被執行時,module.js 中 required 的所有單元測試將會被執行,我們寫的每一個單元測試都可以用獨立的 js 文件進行組織,然后通過 required 方式包含在 module.js 中。單元測試的運行結果會被直接打印出來,當有單元測試失敗時 build 就會失敗。清單 2 展示了一個簡單的 DOH 單元測試 sampleTest.js。
清單 2. DOH 單元測試示例
dojo.provide("tests.sampleTest"); doh.register("tests.sampleTest", [ function test_sample() { doh.assertEqual("b", "a"); } ]); |
將這個單元測試添加到 module.js 中,即在 module.js 的頭部位置中添加一行語句:dojo.require("tests.sampleTest ")
清單 3 展示了這個單元測試運行的結果:
清單 3. 失敗的 DOH 單元測試運行結果
命令行運行方式在很多方面存在著缺陷,例如:無法測試與 DOM 操作相關的代碼,無法測試瀏覽器的兼容性等等。而瀏覽器運行方式就能夠彌補這些缺陷。可是將瀏覽器運行方式集成到 Ant build 中會相對復雜一些。這種方式需要一個可訪問服務器的支持,這個服務器可以是一個部署好的公用服務器,也可以是在 build 中啟動的一個本地服務器,下面以本地服務器為例。在 build 中啟動一個本地的 Web 服務器可以使用嵌入式的 Web 服務器,例如 Jetty。 在瀏覽器運行方式中,主入口是一個 html 文件,例如 runner.html。我們可以將該文件放在 WebContent 的根目錄中,并將啟動的 Web 服務器的 Web 應用根目錄設置為 WebContent,這樣就可以通過 http://localhost/runner.html 訪問。 所以在 Ant build 中啟動單元測試就變得簡單了,只需要啟動一個瀏覽器并且訪問該地址即可,這里的瀏覽器可以是任何想要測試的瀏覽器,也可以將每種瀏覽器測試一遍。以 Firefox 為例,Ant 片段如清單 5 所示。 清單 5. Ant 中啟動瀏覽器
其中,executable 是瀏覽器應用程序可執行文件或命令的路徑,arg 是訪問 runner.html 的 web 路徑。這條命令可以達到啟動單元測試的目的,但是當瀏覽器被啟動起來以后這條命令就直接返回了,所以 Ant build 可能在單元測試執行結束之前就已經返回了,無法得到單元測試的執行結果。所以我們需要一個辦法讓 Ant build 等待單元測試執行結束。這時候可以借助 Web 服務器來傳遞這個消息。 我們可以實現一個服務器端的消息轉接服務,該服務可以通過 HTTP 寫入或者讀取單元測試的執行結果。在 runner.html 中添加一段 JavaScript 代碼用于在單元測試執行結束后將結果通過 Ajax 方式寫入到服務中。除此之外,我們還需要實現一個 Java 可執行類,該類以一定間隔從服務器端的服務中去取執行結果,當無法取得執行結果時等待一定間隔重試,直到取得執行結果,然后輸出執行結果并且根據執行結果 是否成功決定返回結果。在 Ant build 中,當單元測試被啟動后啟動該 Java 可執行類。通過這個方式我們可以讓 Ant build 等待單元測試執行結束并且將單元測試的結果輸出,當單元測試失敗時讓 build 失敗。
|