这是我参与8月更文挑战的第17天,活动详情查看:8月更文挑战
这个标题可能听起来有点不是那么好理解,什么叫基于行为的测试?其实是一个相对的概念,因为之前的测试理念是检查预期的结果对不对,但如果是一个行为,就很难通过这种方式验证。
class Publisher {
List<Subscriber> subscribers = []
int messageCount = 0
void send(String message){
subscribers*.receive(message)
messageCount++
}
}
interface Subscriber {
void receive(String message)
}
class PublisherSpec extends Specification {
Publisher publisher = new Publisher()
}
这种情况下,要怎么验证Publisher确实把消息发送出去了呢?按照之前assert的方式,也不是不行,但比较困难。可能需要写比业务代码多很多的代码来验证,那就直接劝退了。这种情况下要怎么办呢,spock就提出了基于行为的测试。说白了,就是需要mock一些对象,但支持mock的单测框架也多如牛毛,但几乎很少有像spock这样简洁好用的。下面上例子: 首先预置对象:
class PublisherSpec extends Specification {
Publisher publisher = new Publisher()
Subscriber subscriber = Mock()
Subscriber subscriber2 = Mock()
def setup() {
publisher.subscribers << subscriber // << is a Groovy shorthand for List.add()
publisher.subscribers << subscriber2
}
这里的门道也很简单,直接用mock()方法就可以mock对象,你也可以把对象传到参数里,但这里支持类型推导,就可以不用写了。mock完之后,把subscribers注册到publisher中,这样基础的工作就准备完毕,下面开始写测试:
def "should send messages to all subscribers"() {
when:
publisher.send("hello")
then:
1 * subscriber.receive("hello")
1 * subscriber2.receive("hello")
}
这里在then的模块中,表达式前面有个 1* 表示要执行几次,这里只发送一次,那么就只会收到1次才是符合预期的。这就是基于行为的测试,代码中只关注发送和接收的行为,其余部分的工作只要用很少部分的代码就能完成。
按照管理,spock如果只做到这么简单,那就不是spock了。下面正片开始:
1 * subscriber.receive("hello") // 1次请求
0 * subscriber.receive("hello") // 0次请求
(1..3) * subscriber.receive("hello") // 1-3次请求,包括1和3
(1.._) * subscriber.receive("hello") // 最少1次
(_..3) * subscriber.receive("hello") // 最多3次
_ * subscriber.receive("hello") // 任意次
还可以在方法体里面写表达式:
1 * subscriber.receive({ it.size() > 3 && it.contains('a') })
当然还有一些更细节的,更进阶的操作,这里就不再一一列举,有需要可以关注他们的官网文档。