当前位置: 首页 > 知识库问答 >
问题:

Spock-使用数据表测试异常

田普松
2023-03-14

如何使用Spock以良好的方式(例如数据表)测试异常?

示例:具有一个方法validateUser,该方法可以抛出不同消息的异常,或者如果用户有效,则不抛出异常。

规范类本身:

class User { String userName }

class SomeSpec extends spock.lang.Specification {

    ...tests go here...

    private validateUser(User user) {
        if (!user) throw new Exception ('no user')
        if (!user.userName) throw new Exception ('no userName')
    }
}

变体1

这一个正在运行,但真正的意图被所有的when/then标签和反复调用validateUser(用户弄得一团糟。

    def 'validate user - the long way - working but not nice'() {
        when:
        def user = new User(userName: 'tester')
        validateUser(user)

        then:
        noExceptionThrown()

        when:
        user = new User(userName: null)
        validateUser(user)

        then:
        def ex = thrown(Exception)
        ex.message == 'no userName'

        when:
        user = null
        validateUser(user)

        then:
        ex = thrown(Exception)
        ex.message == 'no user'
    }

变式2

这个不工作,因为Spock在编译时提出了这个错误:

异常条件只允许在'然后'块

    def 'validate user - data table 1 - not working'() {
        when:
        validateUser(user)

        then:
        check()

        where:
        user                         || check
        new User(userName: 'tester') || { noExceptionThrown() }
        new User(userName: null)     || { Exception ex = thrown(); ex.message == 'no userName' }
        null                         || { Exception ex = thrown(); ex.message == 'no user' }
    }

变式3

这个不工作,因为Spock在编译时提出了这个错误:

异常条件仅允许作为顶级语句

    def 'validate user - data table 2 - not working'() {
        when:
        validateUser(user)

        then:
        if (expectedException) {
            def ex = thrown(expectedException)
            ex.message == expectedMessage
        } else {
            noExceptionThrown()
        }

        where:
        user                         || expectedException | expectedMessage
        new User(userName: 'tester') || null              | null
        new User(userName: null)     || Exception         | 'no userName'
        null                         || Exception         | 'no user'
    }

共有3个答案

贝礼骞
2023-03-14

您可以使用返回消息或异常类的方法或两者的映射来包装方法调用。。。

  def 'validate user - data table 2 - not working'() {
        expect:
            expectedMessage == getExceptionMessage(&validateUser,user)
        where:
        user                         || expectedMessage
        new User(userName: 'tester') || null
        new User(userName: null)     || 'no userName'
        null                         || 'no user'
    }

    String getExceptionMessage(Closure c, Object... args){
        try{
            return c.call(args)
            //or return null here if you want to check only for exceptions
        }catch(Exception e){
            return e.message
        }
    }
令狐钧
2023-03-14

这是我想出的解决办法。它基本上是变体3,但它使用try/catch块来避免使用Spock的异常条件(因为这些条件必须是顶级的)。

def "validate user - data table 3 - working"() {
    expect:
    try {
        validateUser(user)
        assert !expectException
    }
    catch (UserException ex)
    {
        assert expectException
        assert ex.message == expectedMessage
    }

    where:
    user                         || expectException | expectedMessage
    new User(userName: 'tester') || false           | null
    new User(userName: null)     || true            | 'no userName'
    null                         || true            | 'no user'
}

一些警告:

  1. 您需要多个捕获块来测试不同的异常。
  2. 您必须在try/cat块中使用显式条件(assert语句)。
  3. 你不能把你的刺激和反应分成当-然后块。
余铭晨
2023-03-14

推荐的解决方案是有两种方法:一种是测试好的情况,另一种是测试坏的情况。然后这两种方法都可以使用数据表。

示例:

class SomeSpec extends Specification {

    class User { String userName }

    def 'validate valid user'() {
        when:
        validateUser(user)

        then:
        noExceptionThrown()

        where:
        user << [
                new User(userName: 'tester'),
                new User(userName: 'joe')]
    }

    def 'validate invalid user'() {
        when:
        validateUser(user)

        then:
        def error = thrown(expectedException)
        error.message == expectedMessage

        where:
        user                     || expectedException | expectedMessage
        new User(userName: null) || Exception         | 'no userName'
        new User(userName: '')   || Exception         | 'no userName'
        null                     || Exception         | 'no user'
    }

    private validateUser(User user) {
        if (!user) throw new Exception('no user')
        if (!user.userName) throw new Exception('no userName')
    }

}
 类似资料:
  • 全面披露:我对Geb和Spock都很陌生。

  • 我用Spock测试Java代码。我测试这段代码: 我写了一个测试: 它失败是因为抛出了另一个CustomException。但是在块中,我捕获这个异常并抛出一个,因此我希望我的方法将抛出,而不是。如何测试它?

  • 我正在将Grails2中的一系列单元测试升级到Grails3,并在使用Spock数据驱动测试格式驱动测试的域测试中遇到问题。 当我执行测试时,因为测试执行没有填充测试中的错误、字段和val引用。如前所述,这个测试适用于Grails2.5.5,所以我怀疑我缺少了Grails3中需要的一些东西。 Edited:我删除了原来在setup()中的mockForConstraints()调用,使其无效。

  • 我希望在Spock中使用@WithMockUser运行一个参数化测试,每个迭代都有不同的角色。 作为一个示例,下面的测试代码没有显示编译错误,并且运行两次。但是结果失败了,因为#role只在@unroll中解析,而不在@WithMockUser注释中解析。 所以我的问题是:有可能运行这样一个参数化的测试吗?

  • 在我的应用程序中有,它有一个操作,如下所示: 现在,我正在测试视图和模型,如下所示: 但是我的测试用例失败了,stacktrace如下: 正在运行2个spock测试。。。第1页,共2页 有什么问题吗。

  • 我正在使用spock框架为Spring 3控制器类编写测试。我在尝试执行其中一个测试(GET请求)时收到以下错误。请注意,同一类中的所有其他测试(POST请求)都按预期工作。 控制器签名 斯波克试验 组织。springframework。网状物util。NestedServletException:请求处理失败;嵌套的异常是java。lang.IllegalArgumentException:参数