March 14 16:50~18:50; 21:25~22:12
▲節錄自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目錄還不是綠色的。
▼這時候在groovy目錄按滑鼠右鍵,選擇New,只出現新增Groovy Script,並不能新增Groovy Class,表示還沒設定完畢。
▼在groovy目錄按滑鼠右鍵,選擇Mark Directory as—>Test Sources Root。
▼此時groovy目錄變成綠色,按下滑鼠右鍵出現Groovy Class。
***
安裝Spock外掛
▼選擇IntelliJ IDEA—>Preferences…
▼在Plugins分類中搜尋spock,沒找到任何東西因為還沒安裝。點選畫面中央的Search in repositories。
▼找到Spock Framework Enhancements外掛,選擇Install。
▼安裝完畢之後選擇Restart IntelliJ IDEA。
▼這時候選擇New就會看到Spock Specification選項。
***
Eiffel語言定義Stack的行為
▼Design By Contract(DBC,依合約設計)是一種很知名用來定義類別行為的方法,在練習用Spock定義類別行為之前先看一下Eiffel語言對於Stack的push與pop這兩個函數行為的合約。其中require代表定義pre-condition,ensure代表定義post-condition,這就是合約(contract)。
▼以下是pop函數的合約,invariant關鍵字定義class invariant,代表無論何時只要物件存在都必須要滿足的條件。Class invariant也是合約的一種。
***
用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的差異與相似處。
▼執行結果,兩個測試案例(可執行規格)都通過。以上這兩個測試案例當然也可以用JUnit的單元測試來表達,只不過用Spock看起來比較接近自然語言,可讀性比較高一些。
***
延伸閱讀
- 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行為,考慮到邊界條件,定義的範圍更加詳細,有興趣的鄉民可參考。
***
友藏內心獨白:工具沒有唯一,依據時機使用合適的工具。
沒有留言:
張貼留言