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

时间:2015-11-04 18:53:13

标签: testing groovy automated-tests spock

我正在尝试在单个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,那么我应该始终期望完全相同{{1 }和expectedErrorMessage = 'Empty credentials!'。如果由于某种原因(可能是因为源代码中存在错误),我会expectedErrorCode = 10003(或除expectedErrorMessage = Empty!之外的任何其他内容)和'Empty credentials!'(或expectedErrorCode = 10001以外的任何其他内容),这不符合上述要求。

问题是如果两个断言在同一个测试中失败,我只会为第一个断言(此处为1003)收到失败消息。是否有可能在同一测试中获知所有失败的断言?

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

reportedErrorMessage

2 个答案:

答案 0 :(得分:1)

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

  1. 代码中出现assert失败将引发错误,这将停止执行代码。这就是为什么在单个测试中不能有两个失败的断言。 Spock中expectthen块中的任何代码行都有一个隐含的assert
  2. 您正在同一测试中混合正面和负面单元测试。我在自己面前遇到了这个问题,然后我看了/看了一下这个和Spock(我相信来自创作者Peter Niederwieser),并且知道这些应该被分成不同的测试。不幸的是我找不到那个参考。基本上,您需要对失败的用例进行一次测试,并对传递/成功用例进行一次测试。
  3. 鉴于这些信息,这是您的第二个示例代码,将测试分开,第二个测试中的失败方案。

        @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测试用例的评论 - 我不确定它的意图是什么,但我猜他们正在制作几个全部通过的断言,而不是验证某些东西是否失败。

答案 1 :(得分: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

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

希望这有帮助!