l

2017年2月23日 星期四

BDD(8):實作第一個開發票Scenario

Feb. 22 07:15~09:40

屏幕截图 2017-02-22 07.18.39

▲本集範例Scenario

 

Step 1

▼關於Cucumber的基本知識介紹得差不多了,可以開始實作開三聯發票的第一個Scenario。這個Scenario一共有5個step(步驟),首先看到第一個步驟:「Given The VAT rate is 5%」,一開始step definition的實作想法很單純,新增一個Invoice物件,把營業稅5%記錄在它身上。昨天已經介紹過用Percentage類別來支援營業稅用5%或0.05的表示方式,以下的程式碼紅色部分表示語法錯誤,因為Invoice類別和它身上的setVATRate函數都還沒定義。我們眼下的目標就是讓這個step definition至少沒有語法錯誤。

屏幕截图 2017-02-22 07.22.03

 

▼實作Invoice類別和setVATRate函數。

屏幕截图 2017-02-22 07.30.05

 

▼實作完成之後執行測試案例,第一個步驟通過。之後的例子實作完成之後都會執行測試案例,除非特別狀況否則執行結果畫面就不重複擷取。

屏幕截图 2017-02-22 07.35.36

***

Step 2

▼第二個步驟:「And the tax included price is 17000」, 把含稅價格設給Invoice物件,當然Invoice身上沒有setTaxIncludedPrice函數所以出現紅色語法錯誤。

屏幕截图 2017-02-22 07.34.04

 

▼在Invoice類別加上setTaxIncludedPrice函數實作。

屏幕截图 2017-02-22 07.40.00

***

Step 3

▼到目前為止都很簡單,鄉民們可能看到快睡著了。請不要轉台,問題即將出現在第三個步驟:「When  I issue a company invoice」, 開一張發票。這個步驟說要開一張發票,但是Invoice物件已經存在了,顯然之前那兩個步驟的實作似乎沒有反映需求

屏幕截图 2017-02-22 07.43.34

 

▼第三步驟也許應該長成下面這個樣子,透過另一個InvoiceBuilder類別來開一張發票。

屏幕截图 2017-02-22 07.48.54

 

▼回頭修改前兩個步驟,step definition變成下面這樣。

屏幕截图 2017-02-22 07.52.31

 

▼接下來先新增InvoiceBuilder類別,然後套用move method重構把setVATRate和setTaxIncludedPrice移到它身上。

屏幕截图 2017-02-22 07.57.50

 

▼issue函數回傳Invoice物件,並設定Invoice物件擁有含稅價格、營業稅率、營業稅金、未稅價格。getVAT函數用來計算稅金,getTaxExcludedPrice函數用來計算未稅價格,目前都還沒實作。

屏幕截图 2017-02-22 08.12.14

 

▼getVAT和getTaxExcludedPrice實作完成之後發現Invoice少了合適的建構函數。

屏幕截图 2017-02-22 08.19.54

 

▼實作Invoice的建構函數。

屏幕截图 2017-02-22 08.22.58

 

▼跑測試案例,現在前三個步驟都通過了。

屏幕截图 2017-02-22 08.24.27

***

Step 4

▼「Then I should see the VAT is 810」告訴我們發票的稅金應該是810。

屏幕截图 2017-02-22 08.28.20

 

▼在Invoice物件身上實作getVAT函數,

屏幕截图 2017-02-22 08.37.22

 

▼執行測試案例也通過了。

屏幕截图 2017-02-22 08.30.40

***

Step 5

▼最後一個步驟「And the tax excluded price is 16190」。

屏幕截图 2017-02-22 08.36.41

 

▼在Invoice物件身上實作getTaxExcludedPrice函數,

屏幕截图 2017-02-22 08.38.54

 

▼執行測試案例也通過了。Scenario所包含的5個步驟都通過,整個Scenario也就變成綠燈了。

屏幕截图 2017-02-22 08.39.43

***

討論

  • 看到這裡鄉民們對於BDD—行為驅動開發—應該很有軟體開發「被行為推著走(驅動)」的感覺吧。藉由例子定義行為,然後逐一將例子中所規範的行為透過step definition轉成程式實作。其實這也不是什麼新觀念,和20幾年前的RUP強調use case driven的感覺很像,只不過use case的粒度比起一個scenario大很多,用精實開發的術語來說算是「大批量生產」。BDD或Specification by Example的一個例子粒度很小,算是「小批量生產」,這也是精實開發所鼓勵的方式。當然兩者背後的實作細節差異頗大,不過大方向來看都是藉由「行為」來驅動系統的開發步調(use case也是一種定義系統行為的方式)。
  • 另外,這個例子的「商業流程很簡單(幾乎沒有)」,所以鄉民們在step definition看不到什麼商業流程的描述。實做這些step definition的物件也很簡單,也沒什麼複雜的程式邏輯,所以BDD要銜接到TDD的部分在這個例子也看不到。換句話說,還不需要撰寫單元測試來弄清楚InvoiceBuilder與Invoice的行為,因為這兩個類別的行為目前透過step definition已經可以表達清楚了。

屏幕截图 2017-02-22 09.29.55

 

  • Domain Model目前只有兩個類別,是由BDD的過程所探討出來的,而不是採用傳統OOAD方式先找類別、屬性、方法、關係,然後撰寫程式實作。
  • 程式目前還沒重構,可以思考看看有沒有需要重構的地方。

***

友藏內心獨白:這系列的目標快變成從小例子學BDD+TDD+DDD。

 

延伸閱讀

  1. BDD(1):詳盡的文件就是可用的軟體
  2. BDD(2):大家來吃小黃瓜之Cucumber運作原理
  3. BDD(3):在Eclipse執行Cucumber-JVM
  4. BDD(4):第一個Cucumber-JVM範例,上集
  5. BDD(5):第一個Cucumber-JVM範例,下集
  6. 在IntelliJ IDEA使用Cucumber(上)
  7. 在IntelliJ IDEA使用Cucumber(下)
  8. BDD(6):讓Step找到Step Definition
  9. BDD(7):使用Transform讓稅金同時支援5%和0.05表達方式

沒有留言:

張貼留言