l

2017年2月28日 星期二

BDD(11)使用Scenario Outline指定多個範例(下)

Feb. 23 18:43~20:24

屏幕截图 2017-02-23 20.23.35

▲  圖片節錄自Google搜尋結果

 

Debug

開發人員A:看了錯誤訊息,發現這個case的稅金算出來是1元而不是0元,很顯然是稅金計算有問題

屏幕截图 2017-02-23 17.58.29_thumb[4]

屏幕截图 2017-02-23 18.00.09_thumb[1]

 

開發人員B:我記得稅金計算在InvoiceBuilder類別中的getVAT函數,它先呼叫getTaxExcludedPrice函數得到未稅價格,然後再把未稅價格乘上稅率得到稅金。

屏幕截图 2017-02-23 18.55.10

 

開發人員A:哇,這個邏輯有點小複雜,是不是要寫個單元測試來確認一下?

開發人員B:對歐,怎麼之前我們沒測這兩個函數?

開發人員A:因為它們都是private函數,被issue函數給使用。我們是藉由測試issue函數間接測試這兩個private函數

開發人員B:可是現在有bug,如果不對它們做個別的單元測試不太容易看出問題出在哪裡?

開發人員A:我們現在有兩個選擇,要嘛就是把這兩個函數先改成public,等測試完畢找到bug之後再改回private,或是使用一些特殊技巧讓JUnit可以測試private函數。

開發人員B:我覺得這兩個方法都不太好耶,尤其是第一個,先改成public等測試後沒問題再改回private那麼原本的單元測試案例就沒有作用了啊

開發人員A:那怎麼辦?

***

Refactoring

開發人員B:我們分析一下,InvoiceBuilder的責任是產生一個Invoice,getVAT和getTaxExcludedPrice的責任是和計算發票相關金額有關。我們把這兩個函數變成private的原因是我們認為它們只是InvoiceBuilder的實作細節,一個InvoiceBuilder身上如果有發票金額計算公式的確有點怪。但是既然這些公式的邏輯需要釐清,代表「案情並不單純」,會不會有一種責任我們還沒找出來?

開發人員A:你的意思是說這兩個函數應該屬於另外一個類別?

開發人員B:嗯,我們試著新增一個InvoiceCalculator類別看看,然後套用Move Method重構把這兩個private函數移過去。

開發人員A:那我們先幫getTaxExcludedPrice函數寫一個單元測試,輸入含稅價格10和稅率0.05,未稅價格為10。

屏幕截图 2017-02-23 19.21.25

 

開發人員B:因為還沒實作程式碼所以這個測試案例會失敗,現在讓我們把getTaxExcludedPrice從InvoiceBuilder類別移到InvoiceCalculator類別。

屏幕截图 2017-02-23 19.24.28

 

開發人員A:測試案例通過了,看起來bug應該是在getVAT函數身上。

屏幕截图 2017-02-23 19.24.54

 

開發人員B:我們趕快幫getVAT函數寫一個單元測試看看能不能重現這個bug。

屏幕截图 2017-02-23 19.28.39

 

開發人員A:現在來實作getVAT函數。

屏幕截图 2017-02-23 19.29.24

 

開發人員A:跑一下測試案例,果然失敗了。

屏幕截图 2017-02-23 19.32.12

 

開發人員B:奇怪,公式看起來沒錯啊,。

屏幕截图 2017-02-23 19.37.09

 

開發人員A:我們手動驗算看看,未稅價格10 乘上稅率 0.05 = 0.5,四捨五入之後變成1。

開發人員B:但是Product Owner告訴我們,10元以內的營業稅都是0,所以這算是一個特殊狀況。

開發人員A:難道我們要在公式前加上 if 條件句來排除這個狀況嗎?

開發人員B:啊,我想到了。既然計算未稅價格的getTaxExcludedPrice函式是對的,我們只要把getVAT函數改成這樣就可以了。

屏幕截图 2017-02-23 19.42.03

 

開發人員A:對耶,用含稅價格減去未稅價格不就好了,你好棒棒。跑一下單元測試案例確認一下。

屏幕截图 2017-02-23 19.43.04

 

開發人員B:單元測試案例通過了,現在可以回頭修改InvoiceBuilder類別,讓它的實作改呼叫InvoiceCalculator類別。

屏幕截图 2017-02-23 19.46.44

 

開發人員A:驗收測試也通過了,YA,可以跟Product Owner交差了。

屏幕截图 2017-02-23 19.47.37

***

結束這一回合

開發人員們:我們找到問題也改好了,你看原本的驗收測試都通過了,你看一下測試結果。

Product Owner:太好了,辛苦了。

Product Owner:關於開三聯發票還有其他問題嗎?

開發人員們:啊,還有一個問題。可以開0元發票嗎?

Product Owner:可以喔,只不過0元發票不能兌獎,不過能不能兌獎跟我們系統沒關係。我知道你要說什麼:「可以給我一個例子嗎?」例子在此,請服用。

含稅價格 稅金 未稅價格 備註
0 0 0 可以開零元發票

 

開發人員A:好,那我再加一個0元發票的例子。

屏幕截图 2017-02-23 20.03.34

 

開發人員:這9個例子都通過了。

屏幕截图 2017-02-23 20.04.06

 

Product Owner:好,這個scenario就先做到這樣,我們再找時間討論其他scenario。

***

討論

  • 從這個例子可以看出來由BDD銜接到TDD的部分,為了要支援10元免收營業稅的例子,我們用TDD的方式修改了程式設計,把InvoiceBuilder類別與計算發票相關金額有關函數套用Move Method重構移到新的InvoiceCalculator類別中。重構之後的設計也更加符合單一責任原則(Single Responsibility Principle)
  • 「當發現系統有bug,先寫一個失敗的測試案例來反應出這個bug,之後再修改程式直到測試案例通過」,這是敏捷開發中很常見的除錯過程。

***

友藏內心獨白:對於BDD/TDD應該慢慢有點感覺了吧。

2017年2月27日 星期一

BDD(10)使用Scenario Outline指定多個範例(上)

Feb. 23 16:37~18:10

屏幕截图 2017-02-23 18.37.33

▲「米克斯」的三個例子

 

用表格支援多個範例

開發人員們:第一個例子我們已經完成了,關於開三聯式發票還有其他例子嗎?

Product Owner:嗯,那我給你幾組常見的資料,先確定一下你現在的程式是OK的。

含稅價格 稅金 未稅價格 備註
36000 1714 34286 Refactoring定價
17900 852 17048 Scrum早鳥
21000 1000 20000 Scrum定價

 

開發人員們:現在有多個例子,我把原本的Scenario改一下讓它可以支援這種狀況。在Cucumber中可以用Scenario Outline來支援多個例子。

屏幕截图 2017-02-23 17.32.11

 

開發人員們:測試案例都通過了。

屏幕截图 2017-02-23 17.34.31

***

開發人員們:對了,我突然想到一個問題,營業稅5%,如果計算出來的稅金不到一元怎麼辦?

Product Owner:就四捨五入取整數。

開發人員:可以給我一個例子嗎?

Product Owner:如果含稅價格99,計算之後未稅價格是94.28,四捨五入之後得到94。94的5%等於4.7,四捨五入之後得到5,所以稅金要繳5元。

含稅價格 稅金 未稅價格 備註
99 5 94 四捨五入案例

 

開發人員們:好,我把這個例子加進去。

屏幕截图 2017-02-23 17.42.05

 

開發人員們:沒問題,測試案例還是通過。

屏幕截图 2017-02-23 17.43.03

***

找到Bug

Product Owner:對了,講到四捨五入我突然想到,當金額很小的時候因為四捨五入的關係是不用付營業稅的

開發人員:不用付營業稅?可以給我一個例子嗎?

Product Owner:(你沒有別句台詞了嗎?)

Product Owner:一個例子不夠,我一次給你三個。

含稅價格 稅金 未稅價格 備註
1 0 1 邊界條件
10 0 10 邊界條件
11 1 10 邊界條件

 

開發人員們:喔,所以說含稅價格在10元以下營業稅為0,11元要付1元的營業稅為0。

Product Owner:沒錯。

開發人員們:這樣好奇怪喔,如果從未稅價格來看,同樣都是10元但對應到的含稅價格可能是10元或11元。

Product Owner:對啊,規定就是這樣。

開發人員們:好把,我把這三個例子加進去。

屏幕截图 2017-02-23 17.51.24

 

開發人員們:哇,有一個測試案例失敗,就是「含稅價格為10,未稅價格也為10」這一個。

屏幕截图 2017-02-23 17.55.29

 

開發人員:太好了,找到一個問題,我看看是什麼原因。

Product Owner:(就你程式寫的爛啊,不然還有什麼原因!)

***

下集待續…

***

友藏內心獨白:PO可以正面一點嗎XD。

2017年2月26日 星期日

2016吉隆坡、馬六甲、新加坡考察之旅Day4-C夜晚的獨立廣場

Feb. 22 17:25~17:52

▼晚上到獨立廣場旁的歌劇院看介紹吉隆坡的歌劇,晚上少了炙熱的太陽加上打燈之後的獨立廣場味道很不一樣。

Screenshot - 2017_2_22 , 下午 5_26_46

Screenshot - 2017_2_22 , 下午 5_26_59Screenshot - 2017_2_22 , 下午 5_27_06Screenshot - 2017_2_22 , 下午 5_27_11Screenshot - 2017_2_22 , 下午 5_27_12Screenshot - 2017_2_22 , 下午 5_27_15Screenshot - 2017_2_22 , 下午 5_27_17Screenshot - 2017_2_22 , 下午 5_27_30Screenshot - 2017_2_22 , 下午 5_27_32Screenshot - 2017_2_22 , 下午 5_27_36Screenshot - 2017_2_22 , 下午 5_27_39Screenshot - 2017_2_22 , 下午 5_27_42Screenshot - 2017_2_22 , 下午 5_27_44

 

▼時間差不多了先來歌劇院等開演。

Screenshot - 2017_2_22 , 下午 5_27_48

Screenshot - 2017_2_22 , 下午 5_27_56Screenshot - 2017_2_22 , 下午 5_27_57Screenshot - 2017_2_22 , 下午 5_27_59Screenshot - 2017_2_22 , 下午 5_28_00Screenshot - 2017_2_22 , 下午 5_28_01Screenshot - 2017_2_22 , 下午 5_28_05

 

▼偌大的歌劇院只有不到10未觀眾,演員的人數都比觀眾多。演員演得很賣力,還有跟觀眾互動的橋段,體驗一下也匴有趣。

Screenshot - 2017_2_22 , 下午 5_28_14

Screenshot - 2017_2_22 , 下午 5_28_09Screenshot - 2017_2_22 , 下午 5_28_11Screenshot - 2017_2_22 , 下午 5_28_19

***

▼看完歌劇在獨立廣場再逛一下,看到一群機車騎士聚集在此不知道有什麼活動。

Screenshot - 2017_2_22 , 下午 5_28_38

Screenshot - 2017_2_22 , 下午 5_29_02Screenshot - 2017_2_22 , 下午 5_29_03

 

▼打燈之後的清真寺,真的和白天的感覺完全不同。

Screenshot - 2017_2_22 , 下午 5_28_56

 

▼大草坪。

Screenshot - 2017_2_22 , 下午 5_29_24

Screenshot - 2017_2_22 , 下午 5_29_07Screenshot - 2017_2_22 , 下午 5_29_19Screenshot - 2017_2_22 , 下午 5_29_22Screenshot - 2017_2_22 , 下午 5_29_30Screenshot - 2017_2_22 , 下午 5_29_31Screenshot - 2017_2_22 , 下午 5_29_33

 

▼準備回去睡覺了。

Screenshot - 2017_2_22 , 下午 5_30_20Screenshot - 2017_2_22 , 下午 5_30_44

 

***

友藏內心獨白:大大加分的燈光。