前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spock测试框架实践(六)

Spock测试框架实践(六)

作者头像
用户5521279
发布2021-03-10 15:21:33
1.6K0
发布2021-03-10 15:21:33
举报
文章被收录于专栏:搜狗测试搜狗测试

在上一次Spock实践中我们介绍了Spock的文档化测试和HTTP接口测试实践,今天我们用Spock做一些mock的实践。

对于测试来说,除了能够对输入-输出进行验证之外,还希望能验证模块与其他模块之间的交互是否正确,比如“是否正确调用了某个对象中的函数”;或者期望被调用的模块有某个返回值,等等。各类mock框架让这类验证变得可行,而spock除了支持这类验证,并且做的更加优雅,下面我们看一下在Spock里mock的应用实践。

一、mock

首先我们在Spock中创建一个mock对象:

代码语言:javascript
复制
class PublisherSpec extends Specification {
     Publisher publisher = new Publisher()
     Subscriber subscriber = Mock()
     Subscriber subscriber2 = Mock()
     def setup() {
         publisher.subscribers.add(subscriber)
         publisher.subscribers.add(subscriber2)
     }
}

而创建了mock对象之后就可以对它的交互做验证了:

代码语言:javascript
复制
def "should send messages to all subscribers" () {
     when:
     publisher.send( "hello" )

     then:
     1 * subscriber.receive( "hello" )
     1 * subscriber2.receive( "hello" )
}

上面的例子里验证了:在publisher调用send时,两个subscriber都应该被调用一次receive(“hello”)。示例中,表达式中的次数、对象、函数和参数部分都可以灵活定义:

代码语言:javascript
复制
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

得益于groovy脚本语言的特性,在定义交互的时候不需要对每个参数指定类型,如果用过java下的其它mock框架应该会被这个特性深深的吸引住。

二、Stubbing

对mock对象定义函数的返回值可以用如下方法:

代码语言:javascript
复制
subscriber.receive(_) >> "ok"

符号代表函数的返回值,执行上面的代码后,再调用subscriber.receice方法将返回ok。如果要每次调用返回不同结果,可以使用:

代码语言:javascript
复制
subscriber.receive(_) >>> [ "ok" , "error" , "error" , "ok" ]

如果要做额外的操作,如抛出异常,可以使用:

代码语言:javascript
复制
subscriber.receive(_) >> { throw new InternalError( "ouch" ) }

而如果要每次调用都有不同的结果,可以把多次的返回连接起来:

代码语言:javascript
复制
subscriber.receive(_) >>> [ "ok" , "fail" , "ok" ] >> { throw new InternalError() } >> "ok"

三、mock and stubbing

如果既要判断某个mock对象的交互,又希望它返回值的话,可以结合mock和stub,可以这样:

代码语言:javascript
复制
then:
1 * subscriber.receive( "message1" ) >> "ok"
1 * subscriber.receive( "message2" ) >> "fail"

注意,spock不支持两次分别设定调用和返回值,如果把上例写成这样是错的:

代码语言:javascript
复制
setup:
subscriber.receive( "message1" ) >> "ok"
when:
publisher.send( "message1" )
then:
1 * subscriber.receive( "message1" )

此时spock会对subscriber执行两次设定:

  • 第一次设定receive(“message1″)只能调用一次,返回值为默认值(null)。
  • 第二次设定receive(“message1″)会返回ok,不限制次数。

四、其它类型的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.

(在使用此功能之前请三思。在规范下更改代码的设计可能会更好。)

具体的使用方法如果有兴趣可以参考官方文档.

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 搜狗测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档