本文基于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,不限制次数。