2015/8/22

如何使用 Spock 測試 Static Method

使用 Spock 來開發測試程式除了在之前的文章中提到的:可輔助 BDD 的開發流程、與 JUnit 相容及內建 Data Driven 功能等特性之外,還有另外一項優點是內建了 Mock 的功能。Spock 所提供的 Mock 功能在使用上相當的簡潔,以下是一段範例的程式碼:


由以上的程式碼可以看到只要使用 Mock() 函式就可以對指定的對象進行 Mock 的程序,同時也提供二種彈性的宣告方式,一是把要 Mock 的對象傳入 Mock() 函式(第 3, 4 行),另一個方式是使用 Mock() 函式來建立執行個體(第 5 行)。第二種 Java-like 的語法主要是希望在編輯程式碼時 IDE 可以提供較好的支援,執行時會以宣告的型別來判定要產生的 Mock 對象之 Instance。

Spock 所提供的 Mock 功能有另一個亮點是不僅能夠針對 Interface,同時也可以使用在一般的 Class 上。如此在進行系統設計時,就可以不用遷就「是否有辦法分開測試」這個問題而要使用大量的 IoC 在設計之中,以致形成了過度設計的情況。在 Mock Class 前,專案必須要引用 cglib-nodep 和 objenesis 這二個函式庫,所以在 build.gradle 的 dependencies 應該像以下所示範的內容:


根據官方文件的說明,如果要驗證目標 Class 與其週邊 Object 互動的過程是否符合像是循序圖所表達的設計內容,可以使用範例程式中所示範之內容。使用的語法規格是:[互動的次數] * [互動的標的],1 * mockClass.start() 就是驗證 Processor.run 是否有呼叫 ConcreteClass.start(),而且整個 Processor.run 的執行過程中只呼叫一次。

從範例程式中還可以看到,Spock 所提供的 Mock 功能,除了可以用來驗證 Class 間互動過程,同時也具有 Stub 的能力。可以依據呼叫的內容來提供對應的動作,增加了測試程式的靈活性。像範例程式中的第 8 行,當有程式呼中 mockInterface2.getInfo() 時,就會固定傳回 "二號測試字串" 的內容。而在第 15, 16 行,是代表當 Processor.run 的執行過程中,有呼叫到這二個目標函式時所會取得的內容。

雖然 Spock 提供了許多優異的特性,不過,美中不足的地方是目前的版本沒有辦法 Mock 靜態函式。在網路上看了一些討論之後,PowerMock 似乎是一個可用來搭配 Spock 解決這個問題的框架。進一步了解發現 PowerMock 所提供的套件種類繁多,包含了與幾個主流的測試框架整合的功能。而如何在 Gradle 中設定對應的套件,可以讓 Spock 與 PowerMock 協同運作會是一個門檻。

基本上要在 Spock 中使用 PowerMock 來 Mock 靜態函式,會用到 JUnit、Mockito 和 PowerMock 這幾個框架,這使得在設定 build.gradle 內容時更加的棘手。而在測試程式中要把這四個框架整合起來,以便能夠達到 Mock 靜態函式的目的,也是很費心神的一件事。

目前網路上查到的資訊都是片斷的,所以在這裡把相關的資訊統整起來,做為日後研究的起點。以下是 build.gradle 的內容:


以上的套件應該要依照所屬框架更新的狀況來調整對應的版本編號。

在測試程式中,如果有一個以下待測的 Class:


測試程式應該像以下所示範的內容來進行靜態函式的測試:





0 意見:

張貼留言