單元測試框架spock和Mockito應用

先介紹一下兩位主角

spock是一款基於Groovy語言的單元測試框架,其基礎也是JavaJunit,目前最新版已經到了2.0,但對Groovy和響應的Java版本要求較高,具體信息參考:Spock 2.0 M1版本初探spring

Mockito是一個模擬測試框架,可讓你用優雅,簡潔的接口寫出漂亮的單元測試。Mockito可讓單元測試易於可讀,產生簡潔的校驗錯誤。TDD測試驅動開發要求咱們先寫單元測試,再寫實現代碼。在寫單元測試的過程當中,因爲各類依賴的關係致使的阻礙,咱們必需用到Mockito相似的框架來完成資源、對象的模擬。apache

Gradle配置

testCompile 'org.mockito:mockito-core:2.7.22'
    testCompile group: 'org.spockframework', name: 'spock-core', version: '1.3-groovy-2.5'
    testCompile group: 'org.springframework', name: 'spring-test', version: '5.1.9.RELEASE'
    testCompile group: 'org.hamcrest', name: 'hamcrest-library', version: '1.3'
    testCompile group: 'junit', name: 'junit', version: '4.12'
    testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
    testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.2'

Demo代碼

下面是演示代碼:編程

package com.FunTester.mockito.practise

import org.apache.http.client.methods.HttpRequestBase
import org.slf4j.Logger
import spock.lang.Shared
import spock.lang.Specification

import static com.fun.config.Constant.SPACE_1
import static com.fun.frame.SourceCode.getLogger
import static org.mockito.AdditionalAnswers.returnsFirstArg
import static org.mockito.Matchers.anyInt
import static org.mockito.Mockito.*

class Demo extends Specification {

    @Shared
    Logger logger = getLogger(this.getClass().getName())

    @Shared
    List listsss = mock(List)

    @Shared
    HttpRequestBase httpRequestBase = mock(HttpRequestBase.class)

    def setup() {
        logger.info("測試方法開始了")
    }

    def cleanup() {
        logger.info("測試方法結束了")
    }

    def setupSpec() {
        logger.info("測試類[${getClass().getName()}]開始了")
    }

    def cleanupSpec() {
        logger.info("測試類[${getClass().getName()}]結束了")
    }

    def "這是一個普通的demo"() {
        given:"建立一個存根list,添加一些元素"
        List mockedList = mock(List.class);
        mockedList.add("one");
        mockedList.add("two");
        mockedList.add("three times");
        mockedList.add("three times");
        mockedList.add("three times");
        when(mockedList.size()).thenReturn(5);
        mockedList.add("3")
        mockedList.add("3")
        mockedList.add("3")
        mockedList.add("3")

        expect:"驗證屬性以及方法調用次數"
        5 == mockedList.size()
        false == verify(mockedList, atLeastOnce()).add("one")
        false == verify(mockedList, times(3)).add("three times")
        false == verify(mockedList, atMost(4)).add("3")
        false == verify(mockedList, never()).add("30")
    }

    def "這是一個測試的mockito模擬方法返回"() {
        given: "虛擬一個迭代器對象"
        def iterator = mock(Iterator.class)
        when(iterator.next()).thenReturn("hello").thenReturn("world")

        expect: "測試迭代器元素拼接"
        "hello world" == iterator.next() + SPACE_1 + iterator.next()
    }

    def "這是一個測試,用來在對象初始化以後mock對象的"() {
        given: "建立對象後再Mockito"
        def iterator = new ArrayList()
        iterator.add("323")
        def list = spy(iterator)
        doReturn("fun").when(list).get(3)
        doReturn(3).when(list).get(0)

        expect:
        list.contains("323")
        "fun" == list.get(3)
        3 == list.get(0)
    }

    def "這是一個測試,拋出異常的測試用例"() {
        given: "建立測試對象"
        def object = mock(ArrayList.class)
        when(object.get(1)).thenThrow(new IndexOutOfBoundsException("我是測試"))//只能拋出可能的拋出的異常
        def re = 0
        try {
            object.get(1)
        } catch (IndexOutOfBoundsException e) {
            re = 1
        }

        expect:
        re == 1
    }

    def "這是一個測試方法返回值的用例"() {
        given:
        def j = mock(DemoJ.class)
        doAnswer(returnsFirstArg()).when(j).ds(anyInt(), anyInt())

//        when(list.add(anyString())).thenAnswer(returnsFirstArg());
        // with then() alias:
//        when(list.add(anyString())).then(returnsFirstArg());
        expect:
        3 == j.ds(3, 32)

    }

    def "我是測試共享Mock對象的用例"() {
        given:

        when(listsss.get(anyInt())).thenReturn(3)

        expect:
        3 == listsss.get(3)
    }

/**
 *      對於未指定mock的方法,spy默認會調用真實的方法,有返回值的返回真實的返回值,而mock默認不執行,有返回值的,默認返回null
 */
    def "spy和mock區別"() {
        given:
        def list = [1,2,3,4]
        def integers = spy(list)
        when(integers.size()).thenReturn(9)

        expect:
        integers.size() == 9
        integers.get(0) == 1

    }
}
  • 通過個人測試,Mockito的基礎功能在spock應用仍是很是流暢的,可是一些高級語法仍是沒法使用,若是在實際項目中使用請多調研二者差異,大機率仍是要混合編程。

參考文章:api


  • 鄭重聲明:「FunTester」首發,歡迎關注交流,禁止第三方轉載。更多原創文章:FunTester十八張原創專輯,合做請聯繫Fhaohaizi@163.com

技術類文章精選

無代碼文章精選

相關文章
相關標籤/搜索