k框架应该会被这个特性深深的吸引住。
4.4.2.Stubbing
对mock对象定义函数的返回值可以用如下方法:
subscriber.receive(_) >> "ok"
符号代表函数的返回值,执行上面的代码后,再调用subscriber.receice方法将返回ok。如果要每次调用返回不同结果,可以使用:
subscriber.receive(_) >>> ["ok", "error", "error", "ok"]
如果要做额外的操作,如抛出异常,可以使用:
subscriber.receive(_) >> { throw new InternalError("ouch") }
而如果要每次调用都有不同的结果,可以把多次的返回连接起来:
subscriber.receive(_) >>> ["ok", "fail", "ok"] >> { throw new InternalError() } >> "ok"
4.5.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,不限制次数。
4.6.其它类型的mock对象
spock也支持spy,stub之类的mock对象,但是并不推荐使用。因为使用“正规的”bdd思路写出的代码不需要用这些方法来测试,官方的解释是:
Think twice before using this feature. It might be better to change the design of the code under specification
具体的使用方法如果有兴趣可以参考官方文档。
4.7.更多
至此,读者应该对Spock的主要功能和使用方法应该有个粗略的认识。如果希望实际使用spock,推荐读一下官方的文档,写的比较清晰,并且其中引用的一些文档也都值得一读:
http://spockframework.github.io/spock/docs/1.0/index.html
另外一个值得一看的是spock-example工程:
https://github.com/spockframework/spock-example
5.结语
需要再强调一下:现实中的场景绝对会比文章中的例子复杂(比如要mock一个private函数,或者全局变量,或者静态函数,等等),但是此时更好的思路并不是压榨框架的功能,而应该是去思考代码的设计是否出了问题。
还是强调这个观点:单元测试的难度和代码设计的好坏息息相关,单元测试测的三分是代码,七分是设计。如果你觉得自己处于编码能力上升的瓶颈期,那么可以尝试一下为以前写的类编写“纯粹的”单元测试,在这个过程中,spock可以让你从重复的编码、繁重的维护工作中解脱出来,让编写测试回归为一件有幸福感和成就感的事情。