如何使用 Spock 測試 Static Method

Spock 簡易使用說明

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

def "Spock 范例測試程式"() {
    given:
    def mockClass = Mock(ConcreteClass)
    def mockInterface1 = Mock(IInjection)
    IInjection mockInterface2 = Mock()
    Processor tester = new Processor(mockClass)

    mockInterface2.getInfo() >> { "二號測試字串" }

    when:
    tester.run(mockInterface1)

    then:
    1 * mockClass.start()
    1 * mockInterface1.getInfo() >> { "一號測試字串" }
    _ * mockClass.process(_) >> { mockInterface2 }
    1 * mockInterface2.setData(_)
    1 * mockClass.end()
}

由以上的源代碼可以看到只要使用 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 應該像以下所示范的內容:

dependencies {
    testCompile 'org.codehaus.groovy:groovy-all:2.4.4'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
    testCompile 'org.objenesis:objenesis:2.2'
    testCompile 'cglib:cglib-nodep:3.1'
}

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

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

如何 Mock 靜態方法

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

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

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

apply plugin: 'java'
apply plugin: 'groovy'

dependencies {
    testCompile 'org.codehaus.groovy:groovy-all:2.4.4'
    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
    testCompile 'org.objenesis:objenesis:2.2'
    testCompile 'cglib:cglib-nodep:3.1'
    testCompile 'org.mockito:mockito-core:1.10.19'
    testCompile 'org.powermock:powermock-api-mockito:1.6.2'
    testCompile 'org.powermock:powermock-module-junit4:1.6.2'
    testCompile 'org.powermock:powermock-module-junit4-rule:1.6.2'
    testCompile 'org.powermock:powermock-classloading-xstream:1.6.2'
}

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

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

public class TestClass {

    public static String staticMethod() {
        return null;
    }

}

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

import org.junit.Rule
import org.mockito.Mockito
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification

@PrepareForTest([TestClass.class])
class MockStaticMethodSpec extends Specification {

    @Rule
    PowerMockRule mPowerMockRule = new PowerMockRule();

    def "測試靜態方法"() {
        setup :
        PowerMockito.mockStatic(TestClass.class)

        when :
        Mockito.when(TestClass.staticMethod()).thenReturn("測試用字串")

        then :
        TestClass.staticMethod() == "測試用字串"
    }

}
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,316評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,481評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,241評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,939評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,697評論 6 409
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,182評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,247評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,406評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,933評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,772評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,973評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,516評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,209評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,638評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,866評論 1 285
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,644評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,953評論 2 373

推薦閱讀更多精彩內容

  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,781評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,635評論 25 708
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,898評論 6 342
  • 本文介紹了Android單元測試入門所需了解的內容,包括JUnit、Mockito和PowerMock的使用,怎樣...
    于衛國閱讀 4,593評論 0 5
  • 曾走過這樣一條路,它橫臥在兩排銀杏樹間,平坦干凈的地面,被稀疏的綠蔭覆蓋,一雙雙陌生的腳,不停的來回走動著,卻...
    竹鴻初閱讀 227評論 0 1