设为首页 加入收藏

TOP

使用 Spock 框架进行单元测试(五)
2017-12-07 14:22:06 】 浏览:1386
Tags:使用 Spock 框架 进行 单元 测试
出前做一些清理工作,如关闭资源等。

4.3.10.Where Blocks

做测试时最复杂的事情之一就是准备测试数据,尤其是要测试边界条件、测试异常分支等,这些都需要在测试之前规划好数据。但是传统的测试框架很难轻松的制造数据,要么依赖反复调用,要么用xml或者data provider函数之类难以理解和阅读的方式。比如说:

class MathSpec extends Specification {
    def "maximum of two numbers"() {
        expect:
        // exercise math method for a few different inputs
        Math.max(1, 3) == 3
        Math.max(7, 4) == 7
        Math.max(0, 0) == 0
    }
}

而在spock中,通过where block可以让这类需求实现起来变得非常优雅:

class DataDriven extends Specification {
    def "maximum of two numbers"() {
        expect:
        Math.max(a, b) == c
 
        where:
        a | b || c
        3 | 5 || 5
        7 | 0 || 7
        0 | 0 || 0
    }
}

上述例子实际会跑三次测试,相当于在for循环中执行三次测试,a/b/c的值分别为3/5/5,7/0/7和0/0/0。如果在方法前声明@Unroll,则会当成三个方法运行。

更进一步,可以为标记@Unroll的方法声明动态的spec名:

class DataDriven extends Specification {
    @Unroll
    def "maximum of #a and #b should be #c"() {
        expect:
        Math.max(a, b) == c
 
        where:
        a | b || c
        3 | 5 || 5
        7 | 0 || 7
        0 | 0 || 0
    }
}

运行时,名称会被替换为实际的参数值。

除此之外,where block还有两种数据定义的方法,并且可以结合使用,如:

where:
a | _
3 | _
7 | _
0 | _
 
b << [5, 0, 0]
 
c = a > b ? a : b

4.4.Interaction Based Testing

对于测试来说,除了能够对输入-输出进行验证之外,还希望能验证模块与其他模块之间的交互是否正确,比如“是否正确调用了某个某个对象中的函数”;或者期望被调用的模块有某个返回值,等等。

各类mock框架让这类验证变得可行,而spock除了支持这类验证,并且做的更加优雅。如果你还不清楚mock是什么,最好先去简单了解一下,网上的资料非常多,这里就不展开了。

4.4.1.mock

在spock中创建一个mock对象非常简单:

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对象之后就可以对它的交互做验证了:

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”)。

示例中,表达式中的次数、对象、函数和参数部分都可以灵活定义:

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下的其它moc

首页 上一页 2 3 4 5 6 下一页 尾页 5/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇源码 | 批量执行invokeAll() && .. 下一篇Spring、Spring Boot 和 TestNG ..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目