l

2013年7月19日 星期五

BDD(2):大家來吃小黃瓜之Cucumber運作原理

July 17 21:05~23:59

image

 

在《BDD(1):詳盡的文件就是可用的軟體》Teddy提到將使用者需求採用「可執行軟體」來表達的好處,今天以及接下來這一系列文章要介紹Cucumber這個BDD工具(嚴格講起來是Cucumber-JVM)。

***

Feature、Scenario、Step

首先看一個例子,如何將使用者需求以Cucumber來表達:

Feature: Greeting
  Scenario: Say hello world
    Given I have a greeting application with "Hello"
    When I ask it to say hi
    Then I receive "Hello World"

上面這個驗收測試的意思是說:「我有一隻greeting應用程式,在啟動它的時候同時傳給它 "Hello"這個字串。當我呼叫它的hi功能,我會收到 "Hello World"」。雖然上面的驗收測試是用英文撰寫,但Cucumber的驗收測試其實支援40幾種不同的語言,其中包含了正體中文,日後有機會再介紹用正體中文撰寫驗收測試的例子。一個Cucumber的驗收測試檔案要描述在.feature的文字檔當中,這個檔案有三個基本元素:

  • Feature:一個feature代表一個功能,大小相當於一個user story。以ATM(提款機)應用程式為例子,feature包含「身分驗證」 、「提款」 、「轉帳」 、「繳費」 、「餘額查詢」 等 。
  • Scenario:一個功能的操作路徑,以ATM的「提款」feature為例子,可能包含「提款成功」 、「餘額不足」、 「密碼錯誤」 、「卡片無法讀取」、「金資中心連線錯誤」、「提款機現金不足」 、「銀行暫停作業」等scenario。以驗收測試的角度來看,一個scenario就是一個驗收測試案例。因為一個feature可以包含好幾的scenario,所以一個Cucumber的.feature檔案相當於好幾的測試案例,如果這些測試案例全部通過,就代表這個feature通過驗收條件。
  • Step:一個scenario的操作步驟。在Cucumber裡面scenario的標準寫法由given-when-then所組成。Given的步驟用來描述要準備那些測試環境(相當於單元測試裡面的準備test fixture),when的步驟用來描述如何執行待測程式(相當於單元測試裡面的execution),then的步驟用來描述如何驗證測試是否成功(相當於單元測試裡面的assertion)。

螢幕快照 2013-07-17 下午10.19.15

 

如果有寫過use case的鄉民,應該對於feature、scenario、step的這種關係很熟悉。一個use case展開之後有很多執行路徑,每一個執行路徑就是一個scenario,而每一個scenario的執行步驟就是step。所以要把feature想成是一個use case應該也沒什麼不行,只不過從大小的角度來看,一個use case通常包含了若干的user story,也就是說use case比user story大,而且有些use case可能會很複雜。一般來講一個feature裡面通常包含5~20個scenario,如果是use case的話,展開之後的scenario應該很輕易地就會超過這個數量。

***

膠水程式—Step Definition

看到這邊鄉民們應該會有一個疑問:「不是說好了要把需求用可執行軟體的方式來表達嗎?前面那個Cucumber驗收測試範例,也還是一個純文字檔,根本不是可執行軟體啊。」

為了讓非開發人員 (客戶、使用者、Product Owner或測試人員)能夠看懂需求,所以Cucumber的驗收測試是採用「地球人看得懂的語言」(spoken language)來撰寫。當然這樣的純文字檔是無法單獨執行,必須還要有一個機制,告訴Cucumber每一個.feature檔案裡面所描述的step,對應到哪一段可執行程式。這些對應程式(膠水程式)是一個method,在這個method裡面開發人員手動把step的文字描述轉換成相對應的程式碼。以上面這個Greeting feature為例,它包含三個step:

  • Given I have a greeting application with "Hello":開發人員自己寫一個method,在這個method裡面把這個greeting待測程式給new出來,然後傳入"Hello"給greeting程式。
  • When I ask it to say hi:呼叫greeting程式的hi method,並把它的傳回值保存起來。
  • Then I receive "Hello World":比對剛剛呼叫hi method的傳回值是否等於"Hello World",如果是則測試通過。

上面的邏輯寫成Java程式就變成下圖這個鳥樣子挑眉質疑,內容看不懂沒關係,以後會解釋。運作原理就是在method上面貼annotation,Cucumber把這種method稱為Step Definition,是由開發人員負責撰寫的。在執行驗收測試案例的時候,Cucumber會自動做字串比對,把.feature檔案裡面的每一個step連結到每一個step definition method。如果找不到相對應的step definition,Cucumber會丟出錯誤訊息提醒開發人員去定義這些step definition。

螢幕快照 2013-07-19 上午9.15.57

依據BDD的流程,這些step definition一開始的內容都是空的(因為此時待測程式根本還沒開始寫),也就是說這些驗收測試一開始的執行結果都是失敗。等待開發人員實作了待測程式的功能之後,這些驗收測試才會通過。

附帶說明一下,上圖的step definition是用Java程式撰寫,原本Cucumber的step definition是使用Ruby程式撰寫。因為Teddy不懂Ruby,但又想用Cucumber來當作BDD的工具(還記得嗎,Cucumber是用Ruby開發的工具),所以找了一個Cucumber-JVM這個用Java開發的工具,讓開發人員可以用Java程式來撰寫step definition。下一集Teddy會介紹如何在Eclipse裡面使用Cucumber-JVM,敬請期待。

 

螢幕快照 2013-07-17 下午11.58.21

Cucumber測試案例執行結果。

 

***

最後以一張圖作為這一集的結論。

螢幕快照 2013-07-17 下午11.50.23

***

友藏內心獨白:了解之後就覺得蠻簡單的微笑

沒有留言:

張貼留言