本文基於SpringBoot
在pom.xml添加Spock依賴
<!-- test -->
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy-all</artifactId>
<version>2.4.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.spockframework</groupId>
<artifactId>spock-core</artifactId>
<version>1.1-groovy-2.4</version>
<scope>test</scope>
</dependency>
新建Sum.java
1 public class Sum { 2 public int sum(int a, int b) { 3 return a + b; 4 } 5 }
新建groovy測試腳本SpockSpecification.groovy
1 package com.test.bookup 2 3 import com.example.demo.Sum 4 import spock.lang.Specification 5 import spock.lang.Unroll; 6 7 /** 8 * Created by hande on 2018/7/18. 9 */ 10 class SpockSpecification extends Specification{ 11 12 // 調用外部類測試 13 def sum = new Sum(); 14 def "get sum"(){ 15 expect: 16 sum.sum(1,1) == 2 17 } 18 19 // Where Blocks 簡單大小比較函數測試 20 def "get max num"(){ 21 expect: 22 Math.max(a,b) == c 23 24 where: 25 a|b|c 26 1|2|2 27 1|2|2 28 2|3|3 29 } 30 31 def "get min num"(){ 32 expect: 33 Math.min(a,b) == c 34 35 where: 36 a|b|c 37 1|2|1 38 1|2|1 39 2|3|2 40 } 41 42 // 上述例子實際會跑三次測試,相當於在for循環中執行三次測試,如果在方法前聲明@Unroll,則會當成三個方法運行。 43 @Unroll 44 def "@Unroll test"(){ 45 expect: 46 Math.min(a,b) == c 47 48 where: 49 a|b|c 50 1|2|1 51 1|2|1 52 2|3|2 53 } 54 55 // where block另外兩種數據定義方法 56 def "where block data init method"(){ 57 expect: 58 Math.max(a,b) == c 59 60 where: 61 a|_ 62 3|_ 63 7|_ 64 0|_ 65 66 b<<[5,0,0] 67 68 c=a>b?a:b 69 } 70 71 72 73 // When and Then Blocks 74 def "When and Then Blocks"(){ 75 setup: 76 def stack = new Stack(); 77 def em = "push me"; 78 79 when: 80 stack.push(em); 81 82 then: 83 !stack.empty(); 84 stack.size() == 1; 85 stack.peek() == em; 86 } 87 88 89 90 // mock應用 91 Publisher publisher = new Publisher() 92 Subscriber subscriber = Mock() 93 Subscriber subscriber2 = Mock() 94 95 def setup() { 96 publisher.subscribers.add(subscriber) 97 publisher.subscribers.add(subscriber2) 98 } 99 100 def"should send messages to all subscribers"(){ 101 when: 102 publisher.send("hello") 103 104 then: 105 1*subscriber.receive("hello") 106 1*subscriber2.receive("hello") 107 } 108 // 上面的例子里驗證了:在publisher調用send時,兩個subscriber都應該被調用一次receive(“hello”)。 109 }
表達式中的次數、對象、函數和參數部分說明
1 * subscriber.receive("hello") // exactly one call 0 * subscriber.receive("hello") // zero calls (1..3) * subscriber.receive("hello") // between one and three calls (inclusive) (1.._) * subscriber.receive("hello") // at least one call (_..3) * subscriber.receive("hello") // at most three calls _ * subscriber.receive("hello") // any number of calls, including zero 1 * subscriber.receive("hello") // an argument that is equal to the String "hello" 1 * subscriber.receive(!"hello") // an argument that is unequal to the String "hello" 1 * subscriber.receive() // the empty argument list (would never match in our example) 1 * subscriber.receive(_) // any single argument (including null) 1 * subscriber.receive(*_) // any argument list (including the empty argument list) 1 * subscriber.receive(!null) // any non-null argument 1 * subscriber.receive(_ as String) // any non-null argument that is-a String 1 * subscriber.receive({ it.size() > 3 }) // an argument that satisfies the given predicate // (here: message length is greater than 3) 1 * subscriber._(*_) // any method on subscriber, with any argument list 1 * subscriber._ // shortcut for and preferred over the above 1 * _._ // any method call on any mock object 1 * _ // shortcut for and preferred over the above
Stubbing
對mock對象定義函數的返回值可以用如下方法:
subscriber.receive(_)>>"ok"
符號代表函數的返回值,執行上面的代碼后,再調用subscriber.receice方法將返回ok。如果要每次調用返回不同結果,可以使用:
subscriber.receive(_) >>> ["ok", "error", "error", "ok"]
如果要做額外的操作,如拋出異常,可以使用:
subscriber.receive(_)>>{thrownewInternalError("ouch")}
而如果要每次調用都有不同的結果,可以把多次的返回連接起來:
subscriber.receive(_) >>> ["ok", "fail", "ok"] >> { throw new InternalError() } >> "ok"
mock and stubbing
如果既要判斷某個mock對象的交互,又希望它返回值的話,可以結合mock和stub,可以這樣:
then: 1*subscriber.receive("message1")>>"ok" 1*subscriber.receive("message2")>>"fail"
注意,spock不支持兩次分別設定調用和返回值,如果把上例寫成這樣是錯的:
setup: subscriber.receive("message1")>>"ok" when: publisher.send("message1") then: 1*subscriber.receive("message1")
此時spock會對subscriber執行兩次設定:
第一次設定receive(“message1”)只能調用一次,返回值為默認值(null)。 第二次設定receive(“message1”)會返回ok,不限制次數。
