首页 文章

在同一个Spock测试中执行所有断言,即使其中一个断言失败

提问于
浏览
0

我试图在单个Spock方法的上下文中验证两个不同的输出,该方法运行 when-then-where 形式的多个测试用例 . 出于这个原因,我在 then 块中使用了两个断言,如以下示例所示:

import spock.lang.*

@Unroll
class ExampleSpec extends Specification {

     def "Authentication test with empty credentials"() {
         when:
         def reportedErrorMessage, reportedErrorCode
         (reportedErrorMessage, reportedErrorCode) = userAuthentication(name, password)

         then:
         reportedErrorMessage == expectedErrorMessage
         reportedErrorCode    == expectedErrorCode

         where:
         name | password || expectedErrorMessage | expectedErrorCode
         ' '  | null     || 'Empty credentials!' | 10003
         ' '  | ' '      || 'Empty credentials!' | 10003
     }
}

代码是一个例子,其设计要求是如果 namepassword' 'null ,那么我应该总是期望完全相同 expectedErrorMessage = 'Empty credentials!'expectedErrorCode = 10003 . 如果由于某种原因(可能是因为源代码中的错误)我得到了 expectedErrorMessage = Empty! (或 'Empty credentials!' 以外的任何其他内容)和 expectedErrorCode = 10001 (或 1003 以外的任何其他内容),这将无法满足上述要求 .

问题是如果两个断言在同一个测试中都失败了,我只会为第一个断言(这里是 reportedErrorMessage )收到失败的消息 . 是否有可能在同一测试中获知所有失败的断言?

这是一段代码,它演示了没有其他外部代码依赖性的相同问题 . 我知道在这种特殊情况下,将两个非常不同的测试捆绑在一起并不是一个好习惯,但我认为它仍然证明了这个问题 .

import spock.lang.*

@Unroll
class ExampleSpec extends Specification {

    def "minimum of #a and #b is #c and maximum of #a and #b is #d"() {
        expect:
        Math.min(a, b) == c
        Math.max(a, b) == d

        where:
        a | b || c | d
        3 | 7 || 3 | 7
        5 | 4 || 5 | 4  // <--- both c and d fail here
        9 | 9 || 9 | 9
    }
}

2 回答

  • 1

    基于OP的latest comment,它看起来像我之前的答案不同的解决方案会有所帮助 . 我将原来的答案留在原地,因为我觉得它仍然提供了与问题相关的有用信息(特别是分离正面和负面测试) .

    鉴于你想看到所有的失败,而不是只是在失败的第一个断言失败,我建议将所有内容连接成一个布尔AND操作 . 不使用 && 快捷方式运算符,因为它只会运行到第一次检查不满足整个操作 . 我建议使用 & ,以便进行所有检查,无论以前是否有任何检查失败 .

    鉴于上面的 maxmin 示例,我会将 expect 块更改为:

    Math.min(a, b) == c & Math.max(a, b) == d

    发生故障时,它会为您提供以下信息:

    Math.min(a, b) == c & Math.max(a, b) == d
         |   |  |  |  | |      |   |  |  |  |
         4   5  4  |  5 false  5   5  4  |  4
                   false                 false
    

    这将向您显示失败断言的每个部分 . 相比之下,如果您使用 && ,它只会显示第一个失败,如下所示:

    Math.min(a, b) == c && Math.max(a, b) == d
         |   |  |  |  | |
         4   5  4  |  5 false
                   false
    

    如果你对一行进行两次以上的检查,这显然会很快变得混乱 - 但这是你可以在一行上的所有失败信息之间进行权衡,而不是在修复每个单独组件后重新运行测试 .

    希望这可以帮助!

  • 1

    我认为这里有两件不同的事情 .

    • 代码中出现失败的 assert 将引发错误,这将停止执行代码 . 这就是为什么在单个测试中不能有两个失败的断言 . Spock中 expectthen 块中的任何代码行都有一个隐含的 assert .

    • 您正在同一测试中混合正负单元测试 . 我在自己面前遇到了这个问题,然后我看了/看了一下这个和Spock(我相信创作者Peter Niederwieser),并且知道这些应该分成不同的测试 . 不幸的是,我无法对失败的用例进行一次测试,而对于传递/成功用例需要一次测试 .

    鉴于这些信息,这是您的第二个示例代码,测试分离出来,第二个测试中的失败方案 .

    @Unroll
        class ExampleSpec extends Specification {
    
            def "minimum of #a and #b is #c and maximum of #a and #b is #d - successes"() {
                expect:
                Math.min(a, b) == c
                Math.max(a, b) == d
    
                where:
                a | b || c | d
                3 | 7 || 3 | 7
                9 | 9 || 9 | 9
            }
    
            def "minimum of #a and #b is #c and maximum of #a and #b is #d - failures"() {
                expect:
                Math.min(a, b) != c
                Math.max(a, b) != d
    
                where:
                a | b || c | d
                5 | 4 || 5 | 4
            }
        }
    

    至于你对MongoDB测试用例的评论 - 我不确定它的意图是什么,但我猜他们正在做几个断言都是通过,而不是验证某些东西是否失败 .

相关问题