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 囉!

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):

  1. DEBUG
    供除錯參考用的訊息,通常只有在 development 階段才需要,此類訊息是開發者才需要瞭解。為了避免 LOG 檔訊息數量過多影響效能且佔據磁碟容量,一般在 production 階段會關閉 DEBUG 層級的訊息輸出。
  2. INFO
    記錄一些發生的日常事件,例如一位管理者登入、已刪除一筆資料...等。在 development 階段可供開發者搭配除錯需求追蹤功能的測試結果,建議開啟;到 production 階段若開啟則有助於瞭解回溯至某個時間點進行什麼樣的操作,但是增加訊息量,若系統已經運作穩定則可以視情況選擇開啟或關閉。
  3. WARN
    給予開發者或系統管理者警告訊息,這類訊息不一定要立即處置,因為不會對功能操作產生立即或嚴重的影響;在 production 階段仍建議開啟。
  4. 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 訊息也能顯示。

延伸閱讀:


lyhcode by lyhcode
歡迎轉載,請務必註明出處!