l

2017年3月20日 星期一

BDD(19)幫開發票功能加上使用者介面的三種方法

March 20 08:01~10:08

屏幕截图 2017-03-20 09.51.35

▲終於要幫開發票功能接上使用者介面了

 

前言

在〈BDD(18)這是一個End-To-End的Scenario嗎?〉提到scenario儘量不要描述太多使用者介面(UI)的細節,如果要透過UI做自動化驗收測試則可以把連結到UI的程式碼寫在step definition裡面。今天介紹在「開三聯式發票scenario」加上網頁介面的三種方法。

***

直接修改Scenario

▼第一個最簡單的方式就是直接修改scenario,加上透過UI操作系統的描述。例如把原本的scenario從這樣:

屏幕截图 2017-03-20 08.29.10

 

▼加上「Given I am on the invoice Web page」步驟,改成這樣:

屏幕截图 2017-03-20 08.30.01

 

▼如此一來只要在「Given I am on the invoice Web page」的step definition中連結到操作invoice功能的網頁就可以透過UI讓這個scenario變成完整的end-to-end scenario。

屏幕截图 2017-03-20 08.36.23

 

▼這種方法並沒有描述UI細節,只增加一個步驟描述這個scenario的入口點,其實是可以接受的方法。如果一個feature檔案中有多個scenario,也可以利用Cucumber的Background功能,統一把「Given I am on the invoice Web page」放在Background中,這樣就不用每一個scenario都重複描述。

屏幕截图 2017-03-20 08.39.57

 

如果覺得日後開發票功能可能會改成手機或桌機版本,到時候要把「Given I am on the invoice Web page」改成「Given I am on the invoice App screen」這樣很麻煩,也可以把這句改成更中性一點的敘述:「Given I am using the invoice function」,這樣子scenario要接Web、App、或桌上型應用軟體只要改step definition的內容就可以,不需修改feature檔案(不用改需求)。

***

寫在Step Definition裡面

▼如果想維持原本的scenario敘述不變,但又想要透過UI來自動化這個scenario。

屏幕截图 2017-03-20 08.29.10

 

▼第二種做法就是直接把連結到UI的程式碼寫在step definition裡面。這種做法的好處是scenario專心描述企業邏輯,當真的需要連結到UI的時候只需要修改step definition即可,不用動到scenario。

屏幕截图 2017-03-20 08.51.01

 

這種做法有兩個小缺點,首先從scenario檔案看不出每一個scenario的明顯「入口點」。第二個缺點是step definition內容變得有點亂,原本step definition是協助開發人員探索與定義系統實作的介面,現在夾雜了UI的自動化測試程式,很容易混淆原本的意圖。

***

增加Support Layer

▼原本使用Cucumber的步驟由定義feature file開始,接著撰寫step definition,然後透過TDD的方式來完成domain object(production code)的設計與開發。因為step definition直接操作domain object,所以如果要加上透過UI來操作domain object就必須要修改step definition。

屏幕截图 2017-03-20 08.09.40

 

▼為了讓step definition更乾淨,可以在step definition與domain object之間增加一個support layer(支援層),透過這一層來操作domain object。如此一來便可把UI的細節封裝在support layer。

屏幕截图 2017-03-20 09.04.43

 

▼原本step definition直接操作domain object,現在改成透過KnowsTheDomain類別來操作domain object。

屏幕截图 2017-03-20 09.18.59

 

KnowsTheDomain類別很簡單,只是把原本step definition直接操作domain object的程式碼封裝在這裡而已。

屏幕截图 2017-03-20 09.17.02

 

現在思考一下如何重構(refactor)讓我們可以輕鬆切換有UI和沒有UI的自動化驗收測試。在原本的domain object中,開發票的責任由InvoiceBuilder類別負責,只要能夠提供兩種InvoiceBuilder的實作,一種是原本的實作,另外一種是包含UI的實作,如此一來只要讓KnowTheDomain類別的getInvoiceBuilder函數可以依據設定傳回不同的InvoiceBuilder類別實作,就可以達到「輕鬆切換有UI和沒有UI的自動化驗收測試」的目的。這種做法不需要修改scenario,也不用動到step definition。

 

▼首先套用Extract Interface重構,把原本InvoiceBuilder類別的介面抽離出來。

屏幕截图 2017-03-20 09.38.18

 

▼原本的InvoiceBuilder類別改名為InvoiceBuilderImpl,並且實作剛剛抽離出來的InvoiceBuilder介面

屏幕截图 2017-03-20 09.40.31

 

▼新增WebInvoiceBuilder類別,讓它繼承InvoiceBuilderImpl。複寫issue函數,在開發票的時候打開瀏覽器連到開發票系統的網頁畫面,透過網頁完成開發票的動作。

屏幕截图 2017-03-20 09.42.37

 

▼最後透過dependency injection容器(在此使用picocontainer),讀取設定檔來判斷要注入WebInvoiceBuilder類別實例還是InvoiceBuilderImpl類別實例。

屏幕截图 2017-03-20 09.46.12

 

▼如果要透過網頁測試,在設定檔中加入這一行。

屏幕截图 2017-03-20 09.49.35

 

▼執行驗收測試,首先連結到開發票網頁,自動輸入含稅金額與稅率,按下開發票按鈕。

屏幕截图 2017-03-20 09.51.58

 

▼接著看到計算後的稅額和未稅金額。

屏幕截图 2017-03-20 09.51.35

 

▼當然驗收測試也是通過的。

屏幕截图 2017-03-20 09.52.26

***

結論

今天介紹三種scenario串接UI的方法,各有其優缺點。第三種方法看起來最漂亮,但需要花多點設計與重構的功夫。如果鄉民們想要使用第三種方法但覺得scenario裡面沒有敘述功能起始點怪怪的,也可以結合第一種和第三種方法,把功能起始點描述在feature檔的Background裡面,scenario連結UI的實作方式則是用第三種方法來完成,這樣子應該就接近完美了XD。

***

友藏內心獨白:什麼接近完美,明明就很麻煩…Orz。

沒有留言:

張貼留言