spock框架進行單元測試的學習與實踐


單元測試

一個穩定的系統少不了單元測試,單元測試(又稱為模塊測試, Unit Testing)是針對程序模塊(軟件設計的最小單位)來進行正確性檢驗的測試工作。
對於面向對象編程,最小單元就是方法,包括父類、抽象類、或者子類中的方法。
所以單元測試的特點:

  • 測試的是一個代碼單元內部的邏輯,而不是各模塊之間的交互。
  • 無依賴,不需要實際運行環境就可以測試代碼。
  • 運行效率高,可以隨時執行。

而單元測試的應用場景一般主要有這幾個:

  • 測試驅動開發,由於工期限制,幾乎無法實現
  • 對每次代碼修改做回歸測試

spock測試框架

簡介

Spock是基於JUnit的單測框架,提供一些更好的語法,結合Groovy語言,可以寫出更為簡潔的單測,它的語法完全遵循 BDD(行為驅動開發) 風格的結構。同時集成了像 Jmock、Mockito 等語法表達風格於一體,使得它很簡潔有很高的可讀性

與其他單元測試框架對比

Spock相比JUnit有易讀、簡潔、自帶Mock等特性,可以減少單元測試編寫時間,而且bug更少,可讀性更好,寫出的單元測試代碼更優雅,更易於閱讀!
Spock提供了覆蓋Java企業應用的完整的測試生命周期。其他框架,是基於某種需要產生的,比如:Junit單純用於單測,但不提供mock;Mockito提供mock功能,但不提供靜態類的mock;PowerMock提供靜態類mock;
它們之間需要整合,且不容易跟上新的測試場景。Spock提供了全家桶測試,內置了mock和stub功能等,很方便上手

特點

  • 全能,高效,代碼簡介,易讀,方法名支持中文
  • 提供Groovy的closures,類似Java8的lambda表達式
  • Mockito對參數匹配有限制。如果在方法中使用匹配器,那么所有的參數都需要匹配器。Spock不受此限制,可以將實參與實參匹配器混合和匹配
  • Spock區分了Stub和Mock,讓單測更易讀
  • Spock提供了更多詳細的錯誤信息

基礎

關於依賴

依賴如果版本對不上會報各種各樣的錯,所以最好是根據maven倉庫中查看版本,一定要對應上:
比如如果是3.0版本的spock-core,groovy依賴就必須是:

基本用法

需要創建groovy類使用spock,所有的類都要繼承Specification類,如下:

class SpockDemoSpec extends Specification{
    /**
     * 在第一個測試方法開始前執行一遍
     */
    def setupSpec() { println "------------ setupSpec: 所有測試開始之前執行 ------------" }

    /**
     * 每個測試方法開始前都會執行一遍
     */
    def setup() { println "------------ setup:每個測試方法開始之前執行 ------------" }

    /**
     * 每個測試方法后都會執行一遍
     */
    def cleanup() { println "------------ cleanup:每個測試方法結束之后執行 ------------" }

    /**
     * 最后一個測試方法后執行
     */
    def cleanupSpec() { println "------------ cleanupSpec: 所有測試方法結束之后執行 ------------" }

    def "測試given-expect"() {
        given:
        def a = new Random().nextInt(10)
        def b = 2
        expect:
        println a
        a > b
    }

    def "測試where"() {
        expect:
        result == ++id
        // where表格 左邊是參數,右邊是測試結果
        where:
        id | result
        10  | 11
        100  | 101
        1000  | 1001
    }

    def "測試given-when-then"() {
        given:
        // 數據准備
        def a = "houzheng"
        when:
        // 條件判斷
        boolean flag = a.equals("houzheng")
        then:
        // 期望結果
        flag
    }

    def "測試異常thrown"() {
        when:
        // 此方法會拋出RuntimeException
        throw new RuntimeException("模擬異常");
        then:
        // 接收異常
        def ex = thrown(Exception)
        ex.class.name == "java.lang.RuntimeException"
        ex.getMessage() == "模擬異常"
    }
}

Demo執行結果:

  • where: 以表格的形式提供測試數據集合
  • when: 觸發行為,比如調用指定方法或函數
  • then: 做出斷言表達式
  • expect: 期望的行為,when-then的精簡版
  • given: mock單測中指定mock數據
  • thrown: 如果在when方法中拋出了異常,則在這個子句中會捕獲到異常並返回
  • def setup() {} :每個測試運行前的啟動方法
  • def cleanup() {} : 每個測試運行后的清理方法
  • def setupSpec() {} : 第一個測試運行前的啟動方法
  • def cleanupSpec() {} : 最后一個測試運行后的清理方法

springboot中的使用

常用注解

項目中實際使用

筆者目前項目中某個業務的使用

與原來單元測試代碼的對比

打包運行

測試報告輸出

心得體會與總結

  • 兼容性比較差,依賴版本稍微不對,就會報一些莫名其妙的錯誤,而且提示也不明顯,不太好排查
  • 其實雖然說要懂groovy,但是懂java的人還是非常容易上手的,只要給一個demo,基本就能夠寫單測了
  • 如果還想寫的更優雅更高級,那可以去學學groovy,這里放一下筆者的鏈接:https://www.cnblogs.com/houzheng/p/15183586.html , 有興趣可以看看


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM