l

2017年3月23日 星期四

[還少一本書] BDD in Action

March 23 05:52~07:05

屏幕截图 2017-03-15 15.35.30

 

昨天介紹完《Specification By Example》今天緊接著介紹《BDD in Action》,這兩本書都是Manning出版社所出版。從約20年前買了一本Manning出版的Java網路程式設計的書之後,Teddy一直都很喜歡這個出版社的書。如果要學一樣新技術,Manning所出版的書一定是Teddy優先考量的對象。昨天提到《Specification By Example》書中介紹7個流程模式,並沒有介紹工具也沒有程式碼。《BDD in Action》剛好跟它互補,講了很多工具與程式碼。對於學習BDD的人來說,這兩本書一起服用效果更佳。

***

看圖說故事

▼下圖節錄與修改自《BDD in Action》。

屏幕截图 2017-03-23 06.12.01

 

圖中將BDD開發流程分成6個步驟,和昨天介紹SBE的7個流程模式很接近:

  • Business goal:這一步對應到昨天SBE提到的第1個流程模式Deriving scope from goals
  • Features:這一步可視為SBE第2個流程模式Specifying collaboratively的產出物。
  • Examples:相當於SBE第3個流程模式Illustrating using examples
  • Executable specifications:相當SBE第5個流程模式Automating validating without changing specifications
  • Low-level specifications:從這個步驟開始則是銜接到傳統以單元測試為主的TDD範圍,這裡的low-level specifications就是TDD中的第一個步驟,先寫一個失敗的測試案例作為production code(application code)的規格。
  • Application code:就是TDD的第二個步驟,撰寫production code。如果完全對應TDD應該還有第7個步驟Refactoring(重構)才對,但上圖並沒有把Refactoring特別獨立成一個步驟,所以這個步驟可以看成寫production code加上Refactoring。

上圖步驟1~4可以視為傳統上BDD/ATDD的主打範圍,而5~6則是傳統TDD的守備範圍,而步驟4銜接到步驟5則是Teddy在〈BDD(12) 第二個開發票Scenario:從BDD到TDD〉與〈BDD(13)新劇情找到新Bug〉所介紹的轉換過程。

***

把圖展開

上圖並沒有包含SBE其他三個流程模式:Refining the specification、Validating frequently、Evolving a documentation system,下圖是書中上圖的原圖,可以看到步驟4~5展開後,包含了:

  • Living documentation:對應到SEB的Evolving a documentation system
  • Real-time progress reports:對應到SEB的Evolving a documentation system
  • Technical documentation:對應到SEB的Evolving a documentation system
  • Automatic validation:對應到SEB的Validating frequently
  • Working feature:對應到敏捷宣言的Running software或Scrum的Potentially shippable product increment。

屏幕截图 2017-03-23 06.38.22

 

雖然圖中還是沒有特別標示SBE的Refining the specification這個流程模式,但只要把步驟2和步驟3解讀成來回探索的過程,就等於對應到Refining the specification流程模式。

***

如何閱讀

Teddy是先讀了《Specification By Example》(2011年出版)之後才讀了《BDD in Action》(2014年出版)。第一次閱讀《Specification By Example》的時候因為書中完全沒有程式範例,光是看到書中對於這7個流程模式的文字說明覺得稍嫌抽象。後來讀了《BDD in Action》之後,整個感覺的豁然開朗了起來,兩本書互相對照,幾乎可以說《BDD in Action》就是《Specification By Example》這本書的具體範例啊。

對於沒有讀過這兩本書的鄉民,看完這兩篇介紹之後,Teddy建議直接讀《BDD in Action》再回頭讀《Specification By Example》這種閱讀順序。但是,讀《BDD in Action》也有一點小門檻,因為書中所介紹的工具與程式範例非常多,真的要全部搞懂需要很有耐心學習。

***

友藏內心獨白:讀書也需要實例化範例參考比較容易理解啊。

2017年3月22日 星期三

[還少一本書] Specification By Example

March 22 09:00~10:54

屏幕截图 2017-03-15 15.39.38

 

今年因為在北科兼任的「軟體生命週期管理」課程中教BDD,加上明天晚上在C. C. Agile要分享「SBE、BDD、ATDD、TDD、DDD大亂鬥」這個題目,從農曆年後又把《Specification By Example》(以下簡稱SBE)這本書拿出來讀了一次。第二次讀這本書比較有感覺,趁著記憶猶新的時候介紹這本書的內容。

 

從封底開始看

這本書的內容在英文版的封底已經簡短提示四個重點:

  • Common process patterns:本書包含7個「process patterns」(流程模式),書中從Part 2開始用了7章的篇幅來逐一介紹這7個模式。雖然作者用「模式」這個詞彙來介紹他所提出來的7個套用SBE的流程,但書中並沒有使用大家熟知的模式格式。作者提到用模式來記錄SBE的知識還需要一段時間,所以他先把手邊有的資料用比較隨興的方式介紹。希望假以時日這些知識可以被整理成更正式一點的模式,造福像Teddy這種模式愛好者。
  • How to avoid bad practices:既然書中提到7個流程模式,自然就會提到那些不好的做法會偏離這些模式,以及如何避免誤踩雷區。
  • Fitting SBE in our process:書中介紹的7個流程模式並沒有綁定任何特定工具,讀者融會貫通之後可以自行吸納到自己的開發流程之中。例如,在Scrum、XP或Kanban中套用SBE。
  • 50+ case studies:模式之所以被稱為模式,是因為模式針對重複出現的問題提出一個通過驗證的解決方案。本書是作者訪談超過50個案例並加以研究之後所整理出的7個流程模式,書中有大量的業界實踐SBE的佐證資料。書中Part 3特別用了6章來詳細介紹6個不同的案例,值得參考。

***

7個流程模式

本書的7個流程模式為:

  • (1)Deriving scope from goals:專案的範圍要如何界定?如果沒有目標,在專案進行的過程中一下子業務說加入A這個功能產品絕對超級賣,行銷說沒有B這個功能無法跟別人競爭,老闆說A.B…Z這幾個功能優先權都是1。照單全收的情況下最後導致功能膨脹,但預計上市的時程又不能延後。開發人員只好加班趕工,想辦法讓系統「看起來可以動」先過了這一關再說。專案團隊成員爆肝也就算了,更慘的是東西好不容易做出來才發現並不是客戶心中所想要的。沒有人要對這一片混亂負責,最後又怪開發人員做太慢、bug太多。

以上慘劇每天都在發生,這當然是大家想要避免的。所以專案的範圍必須從目標作為出發點,思考這個專案到底要給客戶和公司帶來什麼好處,採用「以終為始」的思考方式,對於達成專案目標沒有直接貢獻的功能應該加以排除,以免做白工。

  • (2)Specifying collaboratively:目標確定之後專案的規格要由誰來定?剛學Scrum的朋友可能會說:「需求是Product Owner負責的啊」需求是由PO排定優先順序這是沒錯,但並不是說所有需求都是PO一個人寫出來的。從敏捷開發的角度來看,需求是團隊一起討論出來的,這當然包含團隊與stakeholder的互動。SBE更加強調這一點,因此提出協作制定需求規格的建議。
  • (3)Illustrating using examples:規格不管是由一個人或是團隊討論而得出,不同的人對於相同規格總是有不同的解讀,這是因為語言與文字存在著模糊性。例如,雖然法律以及大法官對於警察臨檢有著明文規定與解釋令,但不同人對於「警察是否可要求穿拖鞋到小七買飲料的歐吉桑出示身分證」這件事卻很可能有著截然不同的見解。如果可以搭配案例(example)來輔助說明規格,如此不但可以減少對於規格的誤解,這些案例還可以做為日後相同事件發生時的檢驗標準(驗收測試)

屏幕截图 2017-03-22 10.25.40

 

  • (4)Refining the specification:理解與梳理規格是一個迭代的過程,隨著案例一個、一個出現,專案團隊與stakeholder對於規格越來越清楚,因此需要回頭整理原先的規格。
  • (5)Automating validating without changing specifications:等到規格與例子都整理得差不多了之後,就可以開始自動化。這個自動化的過程對應到Cucumber工具就是撰寫step definition,Teddy在BDD系列文章中已經舉過很多次例子。第5條流程模式的重點是:「自動化驗證而無須修改規格」,要做到這一點剛開始並不是很容易,實際做法可參考〈BDD(19)幫開發票功能加上使用者介面的三種方法〉。
  • (6)Validating frequently:既然已經把對於規格的驗收條件給自動化了,就必須要經常驗證這些條件,以確定系統進度與確保系統品質。
  • (7)Evolving a documentation system:最後,這些可自動執行與驗證的規格、例子與程式介面便成為系統的活文件(living documentation)。因為文件內容是由stakeholder與專案團隊共同討論,而且文件與程式碼隨時保持同步,因此是具備實際參考價值的活文件,而不像很多專案文件與程式已經不同步,變成沒有參考價值的死文件。

▼以上7個流程模式可以用下圖表示

屏幕截图 2017-03-22 09.50.59

***

讀中文版還是英文版?

經過Teddy這一番解釋,鄉民們先在腦袋裡面建立起這本書的概念圖,然後再去讀這本書應該比較容易看得懂。這本書有出正體中文版,Teddy也買了一本,內容翻譯的不錯。但是,Teddy對於正體中文版有一點覺得非常、非常的傻眼,那就是:「Specification By Example為什麼要翻譯成『Spec.實例化』?」把一個完整的名詞拆成兩半,前面用英文後面用中文讀起來真的不太習慣,讀正體中文版的時候每看到一次「Spec.實例化」就好像撞到一次牆一樣,思緒就被中斷一次。為什麼不用「實例化規格」、「規格實例化」或是直接用SBE都好。因為這個名詞貫穿整本書,用了「Spec.實例化」這個翻譯真的讓Teddy每看到一次心中就碎念一次啊。

***

友藏內心獨白:這是介紹SBE還是介紹Pattern啊。

2017年3月21日 星期二

【工商服務】看板方法:科技企業漸進變革成功之道(平日班)

March 21 07:50~08:13

屏幕截图 2017-03-21 07.59.54

 

你的專案遭遇到很多問題:一個團隊同時需要處理多個專案、時程延遲、團隊士氣低落、人員流動率高、加班情況嚴重、技術停滯不前、老闆或業務單位不斷地塞新需求。針對以上問題,Scrum敏捷開發法提供了不錯的解法,但是正所謂施政要「因地制宜」,治病要「對症下藥」,有時候Scrum這帖藥方可能不適合你的公司或團隊,因為:

  • 公司採用瀑布式(waterfall)開發流程,短時間不太可能改成Scrum這種敏捷方法。
  • 你是專門搶案子的資訊服務業者,你的團隊手上同時負責很多專案,而Scrum建議一個人最好同時間只處理一個專案,和你的現況衝突。
  • 你的團隊主要在開發新產品,但三不五時會有舊產品的維護需求跑出來,而且這些臨時性的需求都很急,必須要立即處理,因此打亂了Scrum的開發步驟。
  • 你的工作內容與「消防隊員」類似,專門處理突發事件,例如使用者回報的bug修正、客訴案件、公司IT維護與營運專案,不容易在固定的時間點(每個sprint開始的時候)朝開會議安排工作,而需要採用事件驅動的方式,即時的處理需求。
  • 你的團隊成員比較無法一下子接受過於激烈的組織與工作模式調整,依據Scrum的建議立即組成跨職能團隊(cross-functional team)。
  • 雖然可以從Scrum的工作看板(task board)得知每項工作狀態,但標準的工作看板只有「位施工」、「施工中」、「已完成」這三個狀態。你想要可視化更詳盡的工作流程,並從其中觀察出工作瓶頸以求改善之道。
  • 你是老闆、高階主管或專案經理,其實你不關心什麼敏捷不敏捷、精實不精實的,你只想要有一種比較好的方法來管理專案,方便你「切票(切割工作)」和「派票(分派工作)」,以及知道團隊的進度、工作效率和生產力。
  • 你已經採用Scrum,執行成效還不錯,但在開發流程與品質的持續改善方面遇到瓶頸。

 

如果你的專案具有以上任何一種「症狀」,都值得了解另外一種新的敏捷/精實開發方法:看板方法(Kanban Method)。看板以「可視化現有工作流程」為起點,先不要求團隊做出巨大的改變,以減少採用新方法的抗拒。接著,依據團隊的現有人力,設定每一個工作階段的同時施工項目上限,以協助團隊成員聚焦於「把工作完成」,而非不斷地製造「賣不出去的半成品」。 透過視覺化工具,看板方法可協助團隊找出工作瓶頸,並藉由五步驟聚焦法協助排除瓶頸,達到改善團隊工作效率,提升工作品質的目的。

看板可以應用在以下狀況:

  • 幫助新創公司要管理開發流程以便快速找到市場定位
  • 協助開發團隊有效管理手上同時進行的多個專案
  • 增進Scrum團隊的敏捷性與觀察問題的能力
  • 協助擴展大型敏捷開發團隊(例如Scaled Agile Framework, SAFe)
    • 管理IT維護與營運專案的事件驅動型工作
    • 以漸進且比較無痛的方式實施敏捷開發方法
    • 透過視覺化管理工作流程以便觀察與突破工作瓶頸

     

    螢幕截圖 2015-04-26 21.36.24

    ▲課程實況照片。

    ***

    報名網址在此:【看板方法與精實開發實作班】,上課日期2017年4月25、26日(二、三)。

    image

    ***

    友藏內心獨白:流程改善從此開始。

    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。

    2017年3月17日 星期五

    BDD(18)這是一個End-To-End的Scenario嗎?

    March 17 08:58~10:40

    屏幕截图 2017-03-17 10.34.52

     

    考考你

    敏捷開發是一種「價值驅動」的方法,為了交付價值給用戶,user story應該要表達成end-to-end。當stakeholder、PO、開發團隊透過討論之後寫出user story,接著舉出這個user story具體的例子之後,就可以進入開發階段,透過Cucumber、SpecFlow、JBehave、Fit/FitNess、Robot Framework等工具將此scenario自動化。

    ▼下圖是一個Cucumber的例子,鄉民們先把feature類比成user story(概念上feature的粒度較大,可能包含一個或多個user story),scenario就是feature(user story)的一個例子(example,一種執行路徑)。

    屏幕截图 2017-03-17 09.02.06

     

    從敏捷開發的角度來看,既然user story應該寫成end-to-end,那麼身為user story的一種執行路徑的scenario理論上應該也是end-to-end比較合理。針對這個問題,昨天在北科上「軟體生命週期管理」的時候Teddy問學生:「上面這個Scenario是一個End-To-End的Scenario嗎?

    經過討論之後學生的看法分成兩派:

    1. 不是:這個scenario沒有描述使用者介面,使用者無法直接使用,所以不是end-to-end。
    2. 是:這個scenario描述「開三聯發票的系統行為」,雖然從字面上看起來並沒有提到使用者介面,但是使用者介面是一種實作細節,可以在step definition裡面描述。如此一來不管是透過網頁,或是透過手機App來實作這個scenario,都不用改修改它。

    ***

    看似無聊但很重要

    ▼這個問題好像很無聊但實際上卻非常重要,因為它會影響落實BDD的方向,甚至是成敗的重要因素之一。依據BDD發明人Dan North對於BDD的定義:

    屏幕截图 2017-03-17 09.35.30

     

    首先看到outside-in這個字:由外而內,或是用更傳統的說法,由上而下(top-down)。看到由外而內很自然會認為BDD在描述scenario的時候應該從系統最外面,「也就是使用者介面」開始。所以在網路上或書上經常會看到類似的例子:

    Scenario: Login

    Given I am on the login page

    And I input id as “John”

    And I input password as “pwd321”

    When I press the login button

    Then I should be directed to the welcome page

    接著在step definition裡面就看到實作程式碼呼叫Selenium開啟網頁,選擇DOM的某個元素,輸入Scenario中所描述的帳戶、密碼(在這裡是John/pwd321),然後再按下login按鈕,最後驗證網址跳到welcome 頁面。

    這種例子如果是從介紹「工具」,例如Cucumber、SpecFlow、Selenium的角度來看,是很簡單易懂的好例子,但從BDD的角度來看,就不是那麼合適。因為BDD強調透過stakeholder、PO、開發人員的溝通來建立起「通用語言(Ubiquitous Language)」,這個通用語言正是後續開發活動以及living documentation(活的文件)的核心基礎。如果scenario都是從使用者介面切入撰寫,這樣的scenario頂多只是「自動化驗收測試」的文字版本,離「specification by example」還有一大段距離。

    學過use case的鄉民可能還記得,撰寫use case的時候儘量不要相依於使用者介面,這個原則在BDD撰寫scenario的時候同樣適用。物件導向分析與設計(OOAD)透過use case來建立domain model(找出問題領域的重要概念,這些概念在設計階段會變成類別、介面、屬性、或關係)。同樣地,BDD透過scenario(例子)來建立domain model、介面、屬性、關聯。如果你的scenario都在描述使用者介面的元件,step definition裡面都在呼叫Selenium操作網頁元素,那十之八九你的BDD已經變成透過使用者介面驗證系統行為,你的「物件村(domain model)」很可能人丁單薄,很多商業邏輯不是寫在介面中,很可能就直接寫在資料庫中(stored procedure)。

    ***

    所以哩?

    針對以上的討論Teddy有幾點結論:

    • 為了專注於交付價值以及建立通用語言,BDD的scenario應該還是要保持end-to-end或是接近end-to-end。只不過end-to-end裡面關於前端,也就是使用者介面的細節,可以不要直接寫在scenario裡面,而是擺在step definition或是另外建立一層實作輔助層裡面
    • Outside-in(由外而內)並非一定要從使用者介面開始,它的意思應該是從任何你有興趣的事物外圍開始,然後逐步往內探索
    • Cucumber、SpecFlow、JBehave、Fit/Fitness這些工具只是支援BDD開發流程的一(小)環,並非全部。透過工具無法得知BDD的全貌。這也是為什麼《Specification By Example》這本書完全沒有從工具面去討論SBE/BDD要怎麼做,而是把重點放在7個流程模式( process pattern)
    • 你在撰寫use case所曾經犯過的錯誤,絕大部分在用Given-When-Then撰寫Scenario的時候也都可能再次出現。
    • 只要是以物件導向的方式開發軟體,modeling的技能都是重要的。採用BDD/TDD不會讓你自然產生好的domain model。

    ***

    友藏內心獨白:OOAD的知識還是很有用。

     

    延伸閱讀

    2017年3月16日 星期四

    使用Spock規範類別行為 (下):定義Stack行為

    March 14 16:50~18:50; 21:25~22:12

    屏幕截图 2017-03-14 22.00.08

    ▲節錄自Spock官網

     

    前言

    依據〈使用Spock規範類別行為 (上):在IntelliJ IDEA使用Groovy〉所介紹的步驟,現在已經可以在IntelliJ IDEA使用Groovy,但是要使用Spock還需要設定Maven的pom.xml檔案以及在IntelliJ IDEA安裝Spock外掛才算整個環境設定完成。

    ***

    在Java(Maven)專案中使用Groovy

    ▼確定Groovy安裝成功之後,Teddy最終的目的是要在Java專案中使用Spock來規範類別行為。首先新增一個Maven專案叫做SpockTutorial,在pom.xml檔案中加入。

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12version>
            <scope>test</scope>
        </dependency>
       <dependency>
           <groupId>org.spockframework</groupId>
           <artifactId>spock-core</artifactId>
           <version>1.1-groovy-2.4-rc-3</version>
       </dependency>
        <dependency>
            <groupId>org.codehaus.groovy</groupId>
            <artifactId>groovy-all</artifactId>
            <version>2.4.9</version>
        </dependency>
    </dependencies>

    ▼在test目錄下新增groovy目錄,請注意此時groovy目錄還不是綠色的。

    屏幕截图 2017-03-14 17.48.17_thumb

    ▼這時候在groovy目錄按滑鼠右鍵,選擇New,只出現新增Groovy Script,並不能新增Groovy Class,表示還沒設定完畢。

    屏幕截图 2017-03-14 17.43.52_thumb[1]

     

    ▼在groovy目錄按滑鼠右鍵,選擇Mark Directory as—>Test Sources Root。

    屏幕截图 2017-03-14 17.45.47_thumb[1]

     

    ▼此時groovy目錄變成綠色,按下滑鼠右鍵出現Groovy Class。

    屏幕截图 2017-03-14 17.54.43_thumb[1]

    ***

    安裝Spock外掛

    ▼選擇IntelliJ IDEA—>Preferences…

    屏幕截图 2017-03-14 17.54.00

     

    ▼在Plugins分類中搜尋spock,沒找到任何東西因為還沒安裝。點選畫面中央的Search in repositories。

    屏幕截图 2017-03-14 17.55.29

     

    ▼找到Spock Framework Enhancements外掛,選擇Install。

    屏幕截图 2017-03-14 17.55.36

     

    ▼安裝完畢之後選擇Restart IntelliJ IDEA。

    屏幕截图 2017-03-14 17.55.46 

     

    ▼這時候選擇New就會看到Spock Specification選項。

    屏幕截图 2017-03-14 17.56.10

    ***

    Eiffel語言定義Stack的行為

    Design By Contract(DBC,依合約設計)是一種很知名用來定義類別行為的方法,在練習用Spock定義類別行為之前先看一下Eiffel語言對於Stack的push與pop這兩個函數行為的合約。其中require代表定義pre-condition,ensure代表定義post-condition,這就是合約(contract)。

    屏幕截图 2017-03-14 18.28.40

     

    ▼以下是pop函數的合約,invariant關鍵字定義class invariant,代表無論何時只要物件存在都必須要滿足的條件。Class invariant也是合約的一種。

    屏幕截图 2017-03-14 18.28.47

    ***

    用Spock定義Stack行為

    ▼以下是Teddy所寫的StackSpec類別,它繼承了Spock的Specification類別。StackSpec有兩個函數,分別用來定義push與pop的行為。請鄉民們仔細比對StackSpec與上面Eiffel語言範例,從定義行為的角度來看,此兩者是相近的(扣除掉class invariant不論,因為Teddy還不知道如何在Spock規範類似DBC的class invariant)。在StackSpec類別中Teddy特別用given-when-then格式來定義Stack的行為,讓鄉民們比較一下DBC和given-when-then的差異與相似處。

    屏幕截图 2017-03-15 10.05.38

     

    ▼執行結果,兩個測試案例(可執行規格)都通過。以上這兩個測試案例當然也可以用JUnit的單元測試來表達,只不過用Spock看起來比較接近自然語言,可讀性比較高一些。

    屏幕截图 2017-03-14 21.29.21

    ***

    延伸閱讀

    • Martin Fowler有一篇文章〈SpecificationByExample〉提到Specification By Example(在此可視為BDD同義字)和Design By Contract(DBC)之間的比較與應用時機。DBC的概念源自於傳統定義語意的正規方法(formal method),雖然DBC比起正規方法已經簡單很多但也還是比不上用例子來定義行為(規格)要來的簡單。DBC的倡導者對於用例子來定義行為有所批評,但物件的行為真的要全部都用合約(contract)來定義其實並不容易,有時甚至是不太可行。雖然Martin Fowler從來沒有機會用Eiffel語言來完整使用DBC,但他提到在定義介面(interface)的時候,他總是用合約來思考
    • 為什麼防禦性程式設計不好?〉討論DBC與防禦性程式設計的比較。
    • 最後,這裡有另一個用Spock定義的Stack行為,考慮到邊界條件,定義的範圍更加詳細,有興趣的鄉民可參考。

    ***

    友藏內心獨白:工具沒有唯一,依據時機使用合適的工具。

    2017年3月15日 星期三

    使用Spock規範類別行為 (上):在IntelliJ IDEA使用Groovy

    March 14 15:12~16:40

    屏幕截图 2017-03-14 18.06.11

    ▲節錄自Groovy官網

     

    緣起

    Spock是一種測試與定義程式規格的工具,經常使用在BDD/TDD中用來定義類別/方法層次的規格。在之前的BDD系列文章中Teddy直接使用JUnit來撰寫類別的規格,這兩集將簡單介紹如何用Spock達到相同目的。Spock是用Groovy所開發而Groovy是一種JVM語言,所以Spock可以在Java中直接使用。本集首先介紹如何設定IntelliJ IDEA開發環境以支援Groovy,下一集再介紹用Spock來規範Java Stack類別行為的例子,並且和Design By Contract方法作比較。

    ***

    安裝Groovy

    第一件事要先在作業系統中安裝Groovy,安裝方法很簡單,網路上Google一下就有了XD。這裡介紹在macOS安裝Groovy的步驟。

    連到Install Groovy網頁就可以看到詳細的安裝方法,Teddy採用網頁上介紹的SDKMAN! (The Software Development Kit Manager)來安裝,有四個步驟,打開終端機之後執行:

    1. curl -s get.sdkman.io | bash
    2. 接著再開啟一個新的終端機,輸入source "$HOME/.sdkman/bin/sdkman-init.sh"
    3. 然後輸入sdk install groovy
    4. 最後輸入groovy -version,如果看到以下畫面就代表成功了

    屏幕截图 2017-03-14 13.40.36

    ▲安裝好2.4.9版的Groovy

    ***

    新增HelloGroovy專案

    ▼在IntelliJ IDEA新增Groovy專案,此時Groovy library尚未設定。

    屏幕截图 2017-03-14 15.44.33

     

    ▼按下【Create…】按鈕選擇Groovy安裝目錄。這時候傻眼了,SDKMAN把Groovy安裝在/Users/<username>/.sdkman目錄中,這是一個隱藏目錄,怎麼選啊?

    屏幕截图 2017-03-14 15.50.27

     

    ▼按下【cmd】+【shift】+【.】,隱藏目錄就會出現。

    屏幕截图 2017-03-14 15.54.22

     

    ▼點選/Users/<username>/.sdkman/candidates/groovy/current

    屏幕截图 2017-03-14 15.56.44

     

    ▼設定好Groovy library,按【Next】。

    屏幕截图 2017-03-14 15.59.14

     

    ▼把專案名稱設為HelloGroovy,按【Finish】。

    屏幕截图 2017-03-14 16.00.38

     

    ▼產生一個新的Groovy專案

    屏幕截图 2017-03-14 16.02.18

    ***

    印出Hello, Groovy!

    ▼新增一個Groovy Class

    屏幕截图 2017-03-14 16.03.39

     

    ▼沒問題可以動,在console印出Hello, Groovy!

    屏幕截图 2017-03-14 16.08.13

    ***

    友藏內心獨白:歡迎來到JVM大家庭。