l

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行為,考慮到邊界條件,定義的範圍更加詳細,有興趣的鄉民可參考。

***

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

沒有留言:

張貼留言