Exception Spock测试Where块中的异常处理

Exception Spock测试Where块中的异常处理,exception,groovy,spock,data-driven-tests,Exception,Groovy,Spock,Data Driven Tests,我正在测试一个具有一些依赖关系的服务方法;我想断言,如果这些依赖项中的任何一个抛出异常,服务方法应该返回一个默认值 我想写的服务和测试是这样的 static class Service { def dependency1 def dependency2 def dependency3 def method() { try { def foo = dependency1.get() def bar =

我正在测试一个具有一些依赖关系的服务方法;我想断言,如果这些依赖项中的任何一个抛出异常,服务方法应该返回一个默认值

我想写的服务和测试是这样的

static class Service {
    def dependency1
    def dependency2
    def dependency3

    def method() {
        try {
            def foo = dependency1.get()
            def bar = dependency2.get()
            def baz = dependency3.get()
            return " $foo $bar $baz "
        } catch (Exception e) {
            println e
            return ' default value '
        }
    }
}

def 'test Service error handling'() {
    given:
    def dependency1 = Mock(Supplier)
    def dependency2 = Mock(Supplier)
    def dependency3 = Mock(Supplier)
    def serviceUnderTest = new Service(dependency1: dependency1, dependency2: dependency2, dependency3: dependency3)

    when:
    def result = serviceUnderTest.method()

    then:
    result == ' default value '
    dependency1.get() >> closure1
    dependency2.get() >> closure2
    dependency3.get() >> closure3

    where:
    closure1                              | closure2                              | closure3
    {-> throw new Exception('closure1') } | {-> null }                            | {-> null };
    {-> null}                             | {-> throw new Exception('closure2') } | {-> null };
    {-> null}                             | {-> null}                             | {-> throw new Exception('closure3') }
}
此测试不起作用,因为它会导致模拟返回文本闭包,而不是这些闭包的结果。当然,这是由于添加了where块造成的,因为任何mock都可以直接返回单个闭包的结果,即dependency1.get>{throw new Exception}

我是被迫将此作为三个独立的测试来编写的,还是有其他方法可以将它们组合起来?

如果您编写

dependency1.get>>closure1 您的模拟将返回闭包本身,而不是对其进行计算。评估只发生在GroovyString$foo$bar$baz内部,将评估期间发生的错误消息扩展到其中,但不会升级该异常

你想用

dependency1.get>{closure1} 为了修复你的测试。对闭包进行求值,但同时周围的闭包{}确保仅在调用存根方法时才进行求值,而不是在定义存根方法时才进行求值

一些改进意见:

展开测试,将其拆分为多个具有参数化名称的方法,怎么样?这还有一个很好的副作用,可以帮助IDE和Groovy编译器解析不带分号和{->…语法的where:block。 将模拟方法存根在给定的:块中,而不是不属于它们的then:块中,怎么样? 在模拟定义中存根方法,使测试更紧凑,怎么样? 按照Spock手册的建议,在这个简单的例子中,将when:…then:替换为expect:,怎么样? 包装de.scrum_master.stackoverflow.q57172322 导入spock.lang.Specification 导入spock.lang.Unroll 类ServiceDependenciesThrowingErrorsTest扩展了规范{ @展开 def“服务serviceName中的句柄错误”{ 鉴于: def serviceUnderTest=新服务 dependency1:MockSupplier{get>>{closure1}, dependency2:MockSupplier{get>>{closure2}, dependency3:MockSupplier{get>>{closure3} 期望: serviceUnderTest.method==“默认值” 哪里: 服务名称| closure1 | closure2 | closure3 A |{抛出新异常'closure1'}{null}|{null} B{null}{throw新异常'closure2'}{null} C |{null}|{null}{抛出新异常'closure3'} } 静态类服务{ def依赖性1 def依赖性2 def依赖性3 def方法{ 试一试{ def foo=dependency1.get def bar=dependency2.get def baz=dependency3.get 返回$foo$bar$baz }捕获异常e{ 普林顿 返回“默认值” } } } 静态类供应商{ def get{ 好啊 } } } 这就是我的IDE IntelliJ IDEA中展开时测试执行的样子: