2013年8月26日
O'Reilly 新書介紹 JavaScript Testing with Jasmine by Evan Hahn
你的 JavaScript 程式碼需要測試嗎?如果答案為 YES,那麼先選擇一套合適的測試框架,將是重要的第一步。
在敏捷軟體開發(Agile Software Development),許多開發者推崇「BDD(Behavior-driven development)」的實踐方式,當然在 JavaScript 的世界中,也有許多 BDD 的選擇。
《JavaScript Testing with Jasmine》是一本輕薄短小的入門書,只有不到 50 頁的內容,所以一個下午茶的時間,就能讓你輕鬆瞭解 Jasmine 的美麗與哀愁。
JavaScript Testing with Jasmine
JavaScript Behavior-Driven Development
By Evan Hahn
對於第一次接觸 Jasmine 或其他 JavaScript Testing 框架的開發者,其實最重要的事情,並不是完整的學習。而是需要一些足夠的資訊,用來分辨這個框架是否合用。
對許多開發者來說,習以為常的作法,也許是先下載建置好一個測試環境,然後照著框架的 Getting Started 文件苦命 Try。不過時代進步太快速,如果用拼命 Try 的方式來面對新技術,恐怕再多的新鮮肝都不夠應付啊!
所以,換個方式,找個舒適的角落,泡杯咖啡拿起一本書,享受下午茶的閱讀時光,也許就是這類書籍可提供的價值。
有許多 Open Source 的框架本身很優秀,可是卻沒有淺顯易懂的教學文件,容易讓初學者錯過。以 Jasmine 來說,即使開發者已經瞭解 BDD 的精神,但看著 Jasmine 官方文件的範例和教學,恐怕還是很難在短時間之內掌握重點。假如對 BDD 或 Test-driven 不熟悉,卻想在學習使用框架同時也加深對 BDD 的體悟,就更需要一份好的上手指南。
作者 Evan 對許多 JavaScript 開發框架的涉獵,使這本書以簡單明瞭的範例,讓讀者在最短時間吸收到 Key Points,進而幫助決策 Jasmine 是否為適合專案採納的框架。
如果你需要一本鉅細靡遺的參考書,對於 Jasmine 或 BDD 有全面完整性的介紹,那麼請掠過這本書,因為它太精簡輕薄以致於無法涵蓋太多內容。
但如果你想利用一杯咖啡的時間,瞭解 Jasmine 是什麼?如何使用?看簡單的範例及執行結果?那麼請別錯過這本書的電子版,利用 Kindle 或其他電子書裝置閱讀它。
到底 Jasmine 的 BDD 測試案例程式碼長什麼樣子呢?
BDD 是用 DSL(Domain-Specific Language)的風格來撰寫測試代碼,讓一段測試程式本身就容易從字面推敲出背後要達到的測試目的。舉例來說,書中提供的這個範例,我們並不需要透過任何註解,就不難看出這段代碼對 Employee 物件所進行的兩項測試。
describe("employee", function() {
var employee;
beforeEach(function() {
employee = new Employee;
});
it("has a name", function() {
expect(employee.name).toBeDefined();
});
it("has a role", function() {
expect(employee.role).toBeDefined();
});
});
Jasmine 巧妙運用 JavaScript 的函數型程式設計風格,讓測試代碼變得更為容易閱讀。
如果你只看目錄,會以為這本書內容包羅萬象,例如「Jasmine and Node.js」,不過千萬別誤會,它對所有內容都是點到為止,例如關於 Node.js 的部份也僅限於說明 NPM 如何裝...如此而已。
對於 Jasmine 的介紹,這本書確實也比不上 Jasmine 專案首頁的說明詳細。
不過,如果你是一位 JavaScript 開發者,對 BDD 有些興趣,又剛好想認識 Jasmine 框架,並且用划算的方式取得電子書;那這本書將幫你省下一些找資料和消化吸收所需的時間。
更多訊息請參考:
@本文作者 lyhcode 是 O'Reilly Blogger Review Program 會員,將不定期評論最新的熱門軟體技術書籍。
2013年8月7日
Gradle as Minimum Web Server for Testing 超輕量型網頁測試專用伺服器
有些工具產生的靜態網站資料 .html/.js 需要搭配網頁伺服器才能測試,例如 Sencha Designer 製作的 Ext JS 或 Sencha Touch 專案,通常需要啟動 Apache、Tomcat、Nginx 或 Jetty 才方便以瀏覽器進行測試。
這篇提供的 Script 是利用 Gradle 內建的 Jetty Plugin 快速建立測試專用網站伺服器,由於 Gradle 是跨平台、Java 開發的工具,可以簡單利用 GVM 安裝,所以適合滿足測試用網站伺服器快速建立的需求。
以 Sencha Designer 建立的專案來說,假設先 publish 到某一資料夾。
/home/demo/project1_preview
資料夾可能包含以下檔案:
/home/demo/project1_preview/app.html
/home/demo/project1_preview/app.js
測試的需求是利用瀏覽器來存取 app.html,而非直接以 local 檔案方式開啟,此時就需要透過瀏覽器。
在發佈的資料夾下建立一個 build.gradle 設定檔。
/home/demo/project1_preview/build.gradle
編輯為以下設定內容。
apply plugin: 'jetty'
jettyRun.contextPath = '' jettyRun.webAppSourceDirectory = file('.')
jettyRun.httpPort = 8000
然後在 build.gradle 同一個目錄下執行指令:
gradle jettyRun
啟動後就會執行一個麻雀雖小五臟俱全的 Jetty 伺服器,可以讓瀏覽器直接對該資料夾的內容進行 HTTP 管道的存取。
可以利用瀏覽器打開「http://localhost:8000/」存取。
如此一來,就不需要再為測試後即丟的專案,另外設定諸如 Apache 之類的 Web Server 囉!
這篇提供的 Script 是利用 Gradle 內建的 Jetty Plugin 快速建立測試專用網站伺服器,由於 Gradle 是跨平台、Java 開發的工具,可以簡單利用 GVM 安裝,所以適合滿足測試用網站伺服器快速建立的需求。
以 Sencha Designer 建立的專案來說,假設先 publish 到某一資料夾。
/home/demo/project1_preview
資料夾可能包含以下檔案:
/home/demo/project1_preview/app.html
/home/demo/project1_preview/app.js
測試的需求是利用瀏覽器來存取 app.html,而非直接以 local 檔案方式開啟,此時就需要透過瀏覽器。
在發佈的資料夾下建立一個 build.gradle 設定檔。
/home/demo/project1_preview/build.gradle
編輯為以下設定內容。
apply plugin: 'jetty'
jettyRun.contextPath = '' jettyRun.webAppSourceDirectory = file('.')
jettyRun.httpPort = 8000
然後在 build.gradle 同一個目錄下執行指令:
gradle jettyRun
啟動後就會執行一個麻雀雖小五臟俱全的 Jetty 伺服器,可以讓瀏覽器直接對該資料夾的內容進行 HTTP 管道的存取。
可以利用瀏覽器打開「http://localhost:8000/」存取。
如此一來,就不需要再為測試後即丟的專案,另外設定諸如 Apache 之類的 Web Server 囉!
Grails 2/30 使用過濾器(Filters)
Java EE 提供 Filter 機制可對 Request / Response 進行額外的程式處理,例如 Header 資訊、參數資料及產生的 HTML 內容。
有什麼情況需要用到 Filter 呢?舉例來說,如果我們要增加一個統計網站各頁面點擊次數及瀏覽器資訊的功能,可以在每個 controller 的 action 中做處理,然後將這個處理寫成函式重複呼叫使用。但是在 Filter 的幫助下,可以增加一個不會影響各 controller 現有程式碼的 Filter,然後針對特定或全部的網頁存取進行處理。
一個常見的應用範例,是過去開發 Java EE 程式經常遇到的編碼問題,諸如 Tomcat 等 container 對於瀏覽器送來的表單資料,可能需要先經過 getBytes() 的轉換才能解決中文亂碼。
String name = new String((request.getParameter("name")).getBytes("ISO-8859-1"),"utf-8");
因為 Filter 允許在 Request 主程式被執行前先做前置的處理,所以可以將編碼轉換好在交給主程式,在主程式的邏輯中,就不需要添加這種處理編碼的瑣碎細節。
Grails 之所以能正確處理 Request 表單資料的編碼,就是使用 CharacterEncodingFilter 對資料先進行過處理,所以在 Controller 中使用 params 取得的資料都已轉為正確編碼。
Grails 的 Filter 定義方式非常容易,例如:
grails create-filter Some
就會產生 grails-app/conf/test1/SomeFilters.groovy 程式碼,其內容如下。
class SomeFilters {
def filters = {
all(controller:'*', action:'*') {
before = {
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
}
}
在 def filters 區塊內,可以用 DSL 的形式定義多組 Filter,預設定義的 all 是針對所有 controller/action 進行處理的 Filter 範例。
除了可以指定針對哪些 controller 及 action 進行 Filter 處理,也可以利用 uri 參數設定網址格式,當 Request 的網址符合就會進行處理(以 prefix 加上 ** 萬用字元設定)。
someURIs(uri: '/book/**') {
}
以下提供的範例,是利用 Grails Filter 自動將表單資料的日期,轉換成 GORM 可以自動處理的參數形式。
all(controller:'*', action:'*') {
before = {
log.info "Start ${controllerName}-${actionName}-Filter"
params.each {
key, value ->
// Transform value from Ext JS to Grails date style
if (value ==~ /^\d\d\d\d\-\d\d\-\d\dT\d\d:\d\d:\d\d$/) {
// Convert into Date object
//params[key] = Date.parse('yyyy-MM-dd HH:mm:ss', value.replaceFirst('T', ' '))
// Convert into Grails style date string
//params[key] = "${value}Z"
// Convert into GORM properties recognization
params[key] = 'date.struct'
params["${key}_year"] = value.substring(0,4)
params["${key}_month"] = value.substring(5,7)
params["${key}_day"] = value.substring(8,10)
params["${key}_hour"] = value.substring(11,13)
params["${key}_minute"] = value.substring(14,16)
params["${key}_second"] = value.substring(17,19)
log.info "Found ${value} is a Ext JS date format, transform into Grails style"
log.info "params[${key}] = ${params[key]}"
}
}
}
after = { Map model ->
}
afterView = { Exception e ->
}
}
2013年8月1日
Grails 1/30 訊息記錄(Logging)機制
Grails 採用 Apache log4j 作為預設的訊息記錄(logging)機制,提供新建的的專案,立即可用的 LOG 方法,是 Grails 開發者必須瞭解的基礎。
常用的 LOG 可分為四個等級(level):
常用的 LOG 可分為四個等級(level):
- DEBUG
供除錯參考用的訊息,通常只有在 development 階段才需要,此類訊息是開發者才需要瞭解。為了避免 LOG 檔訊息數量過多影響效能且佔據磁碟容量,一般在 production 階段會關閉 DEBUG 層級的訊息輸出。 - INFO
記錄一些發生的日常事件,例如一位管理者登入、已刪除一筆資料...等。在 development 階段可供開發者搭配除錯需求追蹤功能的測試結果,建議開啟;到 production 階段若開啟則有助於瞭解回溯至某個時間點進行什麼樣的操作,但是增加訊息量,若系統已經運作穩定則可以視情況選擇開啟或關閉。 - WARN
給予開發者或系統管理者警告訊息,這類訊息不一定要立即處置,因為不會對功能操作產生立即或嚴重的影響;在 production 階段仍建議開啟。 - ERROR
錯誤訊息是一定要優先處理的問題,在 production 階段一定要開啟並定期追蹤,如果發現錯誤應立即列入 Issue 控管。
新建的 Grails 專案已包含 log 物件,在 Controller、Domain Class 皆可直接存取,依照層級輸出錯誤信息。
log.info "User ${user.id} has been created."
if (....) {
log.warn "It's not a good idea."
}
try {
}
catch (e) {
log.error "BAD News! ..."
}
在預設的設定下,僅有 warn 層級以上的訊息會被顯示在終端機(console)畫面,所以需要先修改 grails-app/conf/Config.groovy 的 log4j { ... } 設定區塊。增加:
info "grails.app"
或
debug "grails.app"
如此才能讓 info 與 debug 層級的 LOG 訊息也能顯示。
延伸閱讀:
訂閱:
文章 (Atom)