使用Ruby實現簡單的事物驅動的web應用的教程_ruby專題

來源:互聯網
上載者:User

簡介

對 Web 應用程式來講,自動化的整合測試是一個非常重要的部分, 然而由於這些測試案例太依賴具體的 Web 頁面的實現細節,這就給編寫和維護帶來的很大的挑戰。 通常來講有兩種方法可以產生 Web 應用程式測試案例。

    手工編寫指令碼:測試人員需要知道 Web 頁面上有哪些表單、輸入框、選擇框、按鈕等,以及這些表單元素的名稱,ID 等屬性,然後才能利用一些工具來編寫測試案例。
    通過工具錄製產生:比如 IBM Rational Functional Tester 就提供了錄製使用者在 Web 介面的操作,自動產生測試案例的功能。

方法 1 需要測試人員瞭解太多的 Web 頁面細節,這就使得測試人員不能把精力集中在商務邏輯上,一旦 Web 頁面發生變化,將不得不花費大量精力更新指令碼。方法 2 能夠自動產生測試指令碼,但是這些指令碼的可讀性很差,導致很難維護。同樣如果 Web 頁面發生變化,測試人員也需要重新錄製所有的指令碼。

那麼有沒有辦法克服上述問題,讓工作更加輕鬆一點呢?答案是肯定的!

例如一個線上的電子書店,對於使用者購書的情境,我們可以用下面的指令碼來進行整合測試 :

login 'test@test.com','pass4you'     // 登入
list_books                           // 列出書籍
add_to_shop_cart  '誰說大象不能跳舞'  // 把《誰說大象不能跳舞》這本書加入到購物車中

讀者可以看到, "login" , "list_books", "add_to_shop_cart" 這些術語已經完全脫離了具體的頁面細節,將不會受到頁面變化的影響, 它們是完全面向業務的,準確的體現了應用的商務邏輯,容易理解、易於維護,並且還能拿來和業務人員進行交流,甚至業務人員自己都能編寫測試指令碼。 有這麼多的優點,那麼如何?它們呢?這正是本文要介紹的重點:利用動態語言 Ruby 來實現“業務驅動”的 Web 應用程式測試。
Ruby 介紹

Ruby,中文意思為紅寶石,但是在電腦領域,它代表一種相當優秀的物件導向的指令碼程式語言。它誕生於 1993 年,近年來隨著 Ruby on Rails 這個“Killer application”在 Web 開發領域迅速躥紅。Ruby 在最初設計時吸收了很多別的語言的精華,例如 perl 語言的文本處理能力,Python 語言的簡單性和可讀性,以及方便的擴充能力和強大的可移植能力,Smalltalk 語言的純物件導向文法思想,這就使它具備了很多其他語言的優點。Ruby 的設計理念是盡量減少編程時不必要的瑣碎工作,讓程式員在完成任務的同時充分的享受編程的樂趣。

Ruby 的特點如下:

    物件導向:在 Ruby 中,一切皆是對象,包括其他語言中的基礎資料型別 (Elementary Data Type),比如整數。

    例如在 Java 中,對一個數求絕對值用 Math.abs(-20), 但在 Ruby 中一切皆對象,-20 這個數也是對象,所以可以這麼做 -20.abs , 是不是更加形象和直觀?
    解釋型指令碼語言:無需編譯,直接執行,開發週期短,調試方便。
    動態性:已經定義的類可以在運行時修改。

本文的重點不是介紹 Ruby 語言本身,有興趣的讀者可以參見 參考資源 部分。
案例分析
51book

為了展示如何使用 Ruby 進行業務驅動的測試,同時又不讓讀者陷入到過多細節中,本文假想了一個簡單的線上購書應用 ( 簡稱 51book),這個應用支援如下主要功能:

    1.登入 : 使用者必須登入才能購買書籍。
    圖 1. 登入

    2.瀏覽書籍:包括按標題搜尋書籍。
圖 2. 瀏覽和搜尋書籍

3.把書籍添加到購物車中,參見 圖 2 中的“Add to cart”連結。
4.改變購物車中書籍的數量,並且重新計算。

業務操作

通過上面的介紹,讀者應該對 51book 有了一個簡單的瞭解,接下來我們考慮如何進行業務驅動的測試,首先需要定義面向業務的操作,這樣才能在測試案例中使用它們。 簡單起見,我們定義如下業務操作:
表 1. 業務操作

領域專用語言 (Domain Specific Language)

所謂領域專用語言(domain specific language / DSL),其基本思想是“求專不求全”,不像通用目的語言那樣目標範圍涵蓋一切軟體問題, 而是專門針對某一特定問題的電腦語言。正如它的名稱所宣稱的那樣,這種語言並不是通用的,只是專註於某個特定的“領域”, 例如 SQL 語言就是資料庫的 DSL,使用 SQL 可以完成各種各樣資料的操作,而不用關心底層的具體資料庫實現。由於“領域專用”,你想用 SQL 來開發一個傳統型應用程式是不可能的。

我們在上一節定義的 login , add_to_shop_cart , change_quantity 就是針對 51book 線上書店的 DSL。

Martin Fowler 把 DSL 分為兩大類:外部 DSL 和內部 DSL。對外部 DSL 來講,構建它需要做的是:(1) 定義面向領域的全新的文法。(2) 用某種語言編寫解譯器或編譯器 ,由於這種語言是全新的,我們有很多工作需要做;那麼對於內部 DSL 來說,我們可以選定一種靈活的語言,選取它一個文法的子集,並且利用這種語言的動態特性進行定製,這樣就避免了重新打造一個全新語言的龐大工作量。

Ruby 語言具備非常豐富的文法和異常靈活的動態特徵,非常適合建立動態 DSL。本文就是利用 Ruby 來建立 51book 面向測試的 DSL。

用 Ruby DSL 實現業務操作
原理

由於 Ruby 是一種動態指令碼語言,是解釋執行的,它提供了對一段文本進行 “evaluate”執行的方法。也就是說,我們可以提供一段文本(不必是完整的程式),Ruby 就可以在一個特定的上下文中執行它,當然這段文本需要符合 Ruby 的文法。

比如我們有一個檔案 bookshop.txt,它包含了如下文本 : login "andy", "pass4you" , 那麼怎麼執行它呢?首先需要一個上下文,我們可以定義一個類來表示:
清單 1. BookshopDSLBuilder

class BookshopDSLBuilder    def self.execute( dsl)     builder=new     builder.instance_eval(File.read(dsl), dsl)    end   def login(user=nil,pwd=nil)     print user     print pwd   end end

上面的代碼非常簡單,需要關注的是靜態方法 execute, 當把 bookshop.txt 作為參數來調用它時,會有什麼情況發生呢 ? 聰明的讀者可能已經猜到了,那就是 user 和 pwd 的值會被列印出來。這段代碼展示了 Ruby 語言的兩個重要特點 :

    instance_eval 方法會把一段文本當做代碼來執行。執行的上下文就是對象 BookshopDSLBuilder。 所以當它碰到文本 "login" 時,會自動調用真正的方法 login。
    在調用一個方法時,可以不加括弧。這就是為什麼 Ruby 會把文本 login "andy","pass4you" 當做一個方法調用的原因。

這兩個特點就給我們搭了一座“橋”,使得我們可以把那個面向業務測試的文本諸如“login”,“add_to_cart”,“search_book”等轉化為對特定方法的調用了。我們就可以在這些方法中實現某些邏輯。
Watir

我們現在已經能夠把業務測試的指令碼和 Ruby 的對象 / 方法串連起來,可是還需要第二座橋把 Ruby 和 Web 應用程式串連起來,這樣才能使業務測試的指令碼驅動 Web 頁面進行測試。我們希望能有一個軟體或工具可以像人一樣來驅動瀏覽器的操作,例如點選連結,填充表單,點擊按鈕等等。當然它也可以檢查頁面的結果,例如期待的文本是否出現等。

開源工具 Watir 就是這樣一個工具,除了具備上述功能外,它和 Ruby 語言還能進行無縫的整合,並且對瀏覽器尤其是 IE 有超強的控制能力。所以我們選取它作為第二座橋。

下面是一個使用 watir 的簡單例子,它進入 Google 的首頁,在搜尋方塊中鍵入 "bookshop", 然後點擊"搜尋"按鈕。 Watir 充分繼承了 Ruby 語言簡單明了的特點,讀者可以看到使用 Watir 的指令碼是相當直觀,相當容易的。
清單 2. Watir 例子

require "watir"ie = Watir::IE.new ie.goto "http://www.google.com"    ie.text_field(:name, "q").set "bookshop"ie.button(:name, "btnG").click

實現 Login

有了上面的兩座“橋”,具體的實現就簡單多了,對於每一個業務操作,我們需要做的是 :

(1) 在一個 Ruby 對象中 (BookshopDSLBuilder) 實現一個同名的方法

(2) 在方法實現中,利用 watir 來操作介面元素。當然前提是我們需要知道介面上有哪些元素。

先來看一看 Login 的實現:
清單 3. Login

class BookshopDSLBuilder  include Test::Unit::Assertions #include ruby unit 的 Assertion  def self.execute( dsl)   builder=new   builder.instance_eval(File.read(dsl), dsl)   builder  end  def initialize   @login_url = 'http://localhost:3000/bookshop/login'  #51Book 的入口  #creat a ie instance   @ie= Watir::IE.new               # 建立一個 Watir 的執行個體 end  def login(user=nil,pwd=nil)   @ie.goto @login_url   @ie.text_field(:id,"user_name").set(user)   # 設定使用者名稱  @ie.text_field(:id,"user_password").set(pwd)  # 設定密碼  @ie.button(:type,"submit").click        # 點擊提交按鈕 end end

實現 add_to_shop_cart

把書籍添加的購物車中這個操作相對複雜,因為它接收的參數是一個書籍的標題,而在介面上"Add to Cart"卻是一個只包含 book id, 不包含標題的連結,所以無法直接定位。
清單 4. Add to Cart

 <table width='100%' class='book'>   <tr>     <td>title:</td>     <td>Agile development</td> # 標題在這裡  </tr>   <tr>     <td>description:</td>     <td>The book of agile development</td>   </tr>   <tr>     <td>price:</td>     <td>30.0</td>   </tr>   <tr>     <td colspan="2"> #Add_To_Cart Link 卻在這裡      <a href='/bookshop/add_to_cart/1' >Add to Cart</a>     </td>   </tr>   </table>

這種情況下就可以利用 Watir 對 xpath 強大的支援,先找到標題,在從標題找到連結,最後點選連結即可。
清單 5. 使用 XPath

def add_to_cart(title)      table = @ie.table(:xpath,      "//table[@class='book']/tbody/tr/td[text()='"+title+"']/../../../")   if table[1][2].text == title     href = table[4][1].links[1].href     @ie.link(:href,href).click   end end

對於其他的業務操作,具體的實現方式也是大同小異,這裡不再一一介紹,有興趣的讀者可以參見 附件 中的代碼,最後我們來看一個面向業務的 Web 頁面測試例子:
清單 6. 一個完整的例子

 login 'andy','pass4you'  add_to_cart 'Agile development' add_to_cart 'Savor Blue' add_to_cart 'Programming Ruby'  change_quantity 'Agile development',10  change_quantity 'Savor Blue',10  change_quantity 'Programming Ruby',10  recalculate_cart  assert_total_price_is 900  search_book 'Ant cookbook' add_to_cart 'Ant cookbook' assert_total_price_is 910

總結

到目前為止,我們已經通過 Ruby 完整的實現了“業務驅動” 的 Web 應用程式測試,實際上我們通過 Ruby 實現了一個面向業務的抽象層,利用 Watir 把業務操作映射到了對 Html 頁面的操作。這樣當 Html 頁面發生了變化的時候,只需要調整映射,而不需要更改業務層的操作。同時由於它們是完全面向業務的,就使得開發人員或測試人員能把精力集中到商務邏輯的測試上,而不用陷入實現的細節。

掌握了該方法以後,讀者可以應用到自己的程式中,可以使得自己的測試編寫簡單,容易理解,易於維護。將會極大的提供 Web 應用程式的測試效率。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.