August 06 09:49~11:18
離上次寫BDD文章一轉眼又過了快兩個禮拜,不知道鄉民們是否還記得《BDD(4):第一個Cucumber-JVM範例,上集》的內容?先幫大家複習一下,在上集中Teddy提到BDD—「行為驅動開發」的六個步驟,並介紹了前面四個步驟:
- 先定義驗收測試條件,也就是應用程式應有的行為。
- 然後執行驗收測試,這時候因為找不到step definition而測試失敗。
- 定義step definition。
- 然後執行驗收測試,這時候因為step definition的內容是空的所以測試失敗。
- 填寫step definition的內容,在這個步驟鄉民們會開始思考production code的設計與實作。
- 當production code完成,整個驗收測試案例便可通過(或是反過來說,當最後驗收案例通過,就代表production code已經完成)。
今天要繼續介紹5、6兩個步驟。
***
在上集中,最後請鄉民們新增一個名為HelloStepdefs的Java class,然後把Console view裡面Cucumber-JVM所顯示的三個step definition拷貝起來複製到HelloStepdefs類別中,如下圖所示。
現在萬事俱備,只欠 東風 production code。接下來要完成上述的步驟5,藉由填寫step definition的內容來協助鄉民們思考production code的設計與實作 。
實作第一個Step Definition
第一個step definition:「I have a greeting application with "Hello"」告訴鄉民們,需要「生出」一隻「greeting application」,並且把"Hello"這個字串傳給他。有了這個行為的定義,就可以填寫第一個step definition的內容,如下圖所示。
在第9行宣告一個Hello類別的instance variable “hello”來代表「greeting application」(類別的名稱可以自己取,不一定要叫做Hello),然後在「 I_have_a_greeting_application_with(String arg1)」這個method裡面,初始化hello,並且把參數arg1傳給hello。arg1在Cucumber-JVM執行測試案例的時候,會帶入使用者在hello_world.feature檔案中第一個step definition內容:「 Given I have a greeting application with "Hello"」用引號所引號起來的參數,也就是"Hello"這個字串。
填寫完第一個step definition之後,鄉民們發現程式根本無法通過編譯,因為Hello類別根本還沒有產生。此為正常現象,所以才叫做BDD啊。要怎麼讓程式可以編譯成功?很簡單,請鄉民們新增一個Hello class,並且幫它產生一個可以接受一個字串參數的constructor(建構元)。然後在Hello class裡面宣告一個字串型態的instance variable "greeting",用來保存constructor傳入的字串參數。
完成Hello class撰寫之後,HelloStepdefs現在已經可以成功編譯。
這時候執行一下JUnit,原本三個step definition都是灰色的,現在第一個step definition已經有一個小勾勾,代表執行測試通過。
切到Console view,發現第二個step definition還沒有定義。
***
實作第二個Step Definition
第二個step definition:「I ask it to say hi」翻譯成「非白話文」的意思,就是告訴鄉民們呼叫hello物件的sayHi method(method名稱可以自己取,不一定要叫sayHi)。
看到這裡鄉民們應該看出個端倪出來,第18行的hello.sayHi()一定也無法通過編譯,因為Hello類別根本沒有sayHi這個method。要讓程式通過編譯,請鄉民們幫Hello類別新增sayHi()這個method。
完成之後HelloStepdefs就可以成功編譯。
這時候執行一下JUnit,只有第一個step definition有一個小勾勾,現在第二個step definition也通過測試。
***
實作第三個Step Definition
終於來到最後一個步驟,第三個step definition:「I receive "Hello World"」翻譯成「非白話文」的意思,就是說呼叫完hello物件的sayHi method之後,會得到"Hello World"這個字。鄉民們可以在第三個step definition「I_receive(String arg1)」這個method裡面,用JUnit的assertEquals(String, String)來比對sayHi是否傳回"Hello World"這個字。在這裡"Hello World"所謂的expected result,就是測試結果的期待值,事先計算好的正確答案。這個expected result已經定義在hello_world.feature檔案中,Cucumber-JVM在執行測試案例的時候會自動傳入給I_receive(String arg1)」這個method。
現在問題來了,剛剛在步驟二實作sayHello()的時候,並沒有傳出任何的資料出來,所以現在沒有東西可以比對。步驟三告訴鄉民們,sayHello()要傳回"Hello World",為了讓測試程式可以通過編譯,要回頭改一下剛剛寫好的程式。
下圖第11行程式中,在HelloStepdefs類別中宣告一個String型態的instance variable “hi”,然後在第20行用hi來接收sayHi()傳回來的資料。最後,在第25行中,拿hi和arg1相比。
因為sayHi()並沒有傳回任何資料,所以此時測試程式無法編譯,請回頭修改sayHi()的實作。
修改完sayHi()之後,測試案例可以通過編譯。
這時候執行一下JUnit,現在三個step definition都有一個小勾勾,代表驗收測試案例的三個步驟全部通過,也就是說production code已經完成客戶所需要的功能了。
***
友藏內心獨白:寫完收工。
沒有留言:
張貼留言