今天繼續(xù)聊下spock 的其他特性,如果沒有看到前面的內(nèi)容,可以點(diǎn)擊這里查看前面的介紹。
1.Mocking
1.1 什么是Mocking
Mocking是一種改變我們的服務(wù)與我們的服務(wù)合作的類的行為的方式。 這是一種有效的方法,可以獨(dú)立測(cè)試業(yè)務(wù)邏輯的依賴關(guān)系。
一個(gè)典型的例子就是用一個(gè)簡(jiǎn)單的假裝來(lái)替換一個(gè)網(wǎng)絡(luò)調(diào)用的類。
5.2. 用spock 來(lái) Mocking
Spock擁有自己的模擬框架,利用了Groovy帶給JVM的有趣概念。 首先,我們來(lái)實(shí)例化一個(gè)Mock:
PaymentGateway paymentGateway = Mock()
在這種情況下,我們的模擬類型是由變量類型推斷的。 由于Groovy是一種動(dòng)態(tài)語(yǔ)言,我們還可以提供一個(gè)類型參數(shù),使我們不必將模擬分配給任何特定的類型:
def paymentGateway = Mock(PaymentGateway)
現(xiàn)在,無(wú)論何時(shí)我們?cè)赑aymentGateway模擬中調(diào)用方法,都會(huì)給出默認(rèn)響應(yīng),而不會(huì)調(diào)用實(shí)際的實(shí)例:
when:
def result = paymentGateway.makePayment(12.99)
then:
result == false
這個(gè)術(shù)語(yǔ)是lenient mocking。 它的意思是未定義的模擬方法將返回合理的默認(rèn)值,而不是拋出異常。 這是在Spock中設(shè)計(jì)的,目的是為了使模擬和測(cè)試更加健壯。
1.3 在Mocks上調(diào)用樁方法
我們也可以配置我們的Mock上調(diào)用的方法以某種方式響應(yīng)不同的參數(shù)。 讓我們嘗試讓我們的PaymentGateway模擬在我們支付20時(shí)返回true:
given:
paymentGateway.makePayment(20) >> true
when:
def result = paymentGateway.makePayment(20)
then:
result == true
這里有趣的是,Spock如何利用Groovy的操作符重載來(lái)樁方法調(diào)用。 對(duì)于Java,我們必須調(diào)用真正的方法,這可能意味著生成的代碼更加冗長(zhǎng),并且可能不那么富有表現(xiàn)力。
現(xiàn)在,讓我們嘗試更多類型的樁。
如果我們停止關(guān)注我們的方法參數(shù)并始終想要返回true,則可以使用下劃線:
paymentGateway.makePayment(_) >> true
如果我們想要在不同的響應(yīng)之間進(jìn)行切換,我們可以提供一個(gè)列表,每個(gè)元素將依次返回:
paymentGateway.makePayment(_) >>> [true, true, false, true]
1.4 驗(yàn)證
我們可能想要用Mock來(lái)做的另一件事是斷言有不同的方法在預(yù)期的參數(shù)上被調(diào)用。 換句話說(shuō),我們應(yīng)該驗(yàn)證與我們的模擬的交互。驗(yàn)證的典型用例是如果我們的模擬方法有無(wú)效返回類型。
在這種情況下,由于沒有結(jié)果讓我們操作,所以我們沒有推測(cè)的行為可以通過測(cè)試方法進(jìn)行測(cè)試。
一般來(lái)說(shuō),如果返回了一些東西,那么被測(cè)試的方法就可以對(duì)它進(jìn)行操作,這就是我們斷言的操作結(jié)果。讓我們?cè)囍?yàn)證一個(gè)帶有void返回類型的方法:
def "Should verify notify was called"() {
given:
def notifier = Mock(Notifier)
when:
notifier.notify('foo')
then:
1 * notifier.notify('foo')
}
Spock正在利用Groovy運(yùn)算符重載。 通過將我們的模擬方法調(diào)用乘以一,我們說(shuō)我們期望它被調(diào)用了多少次。
如果我們的方法根本沒有被調(diào)用或者沒有按照我們指定的次數(shù)被調(diào)用,那么我們的測(cè)試將沒有給我們提供一個(gè)信息量很大的Spock錯(cuò)誤消息。 讓我們通過期待它被調(diào)用兩次來(lái)證明這一點(diǎn):
2 * notifier.notify('foo')
在此之后,讓我們看看錯(cuò)誤消息是什么樣的。 我們會(huì)像往常一樣; 這是相當(dāng)豐富的:
Too few invocations for:
2 * notifier.notify('foo') (1 invocation)
就像樁一樣,我們也可以執(zhí)行更寬松的驗(yàn)證匹配。 如果我們不關(guān)心我們的方法參數(shù)是什么,我們可以使用下劃線:
2 * notifier.notify(_)
或者如果我們想確保它沒有被特定參數(shù)調(diào)用,我們可以使用not操作符:
2 * notifier.notify(!'foo')
總結(jié)
結(jié)合之前的文章,我們通過使用Spock進(jìn)行測(cè)試給出了一些小的分片案例,展示了Spock比典型的JUnit更具表現(xiàn)力。
我們已經(jīng)展示了執(zhí)行數(shù)據(jù)驅(qū)動(dòng)測(cè)試是多么容易,以及通過本地Spock功能如何輕松模擬和斷言。更多的Spock的特性,請(qǐng)查看官方文檔。
歡迎大家繼續(xù)關(guān)注。