能否让Specs2的Result.foreach行为和普通matcher保持一致?
问题原因
这一现象和Specs2的测试结果校验逻辑直接相关:
- 普通的
must断言在可变风格测试套件中执行时会产生副作用,自动将断言结果注册到测试套件的结果列表中,因此你写的每一行must断言都会被校验,哪怕不是测试块的最后一行。你给出的第一个示例中,1 must beEqualTo(2)执行时就已经把失败结果注册到套件,所以测试会如预期失败。 - 而
Result.foreach返回的是单个Result对象,它本身不会触发自动注册的副作用,只有这个Result对象被测试框架捕获到才会参与结果判定。Specs2默认只会取测试块最后一行的返回值作为整个测试的判定依据,中间返回的Result会被直接丢弃。
你写的两个连续Result.foreach的示例中,第一个Result.foreach返回了失败的Result,但因为不是最后一行被直接忽略,最后一行是返回成功的第二个Result.foreach,所以整个测试会被判定为通过。
用and连接两个Result.foreach语句时,and会把两个Result的结果合并为一个新的Result(只要任意一个原Result失败,合并结果就是失败),这个合并后的Result作为测试块最后一行的返回值被框架捕获,就会如预期失败。
解决方案
可以通过以下几种方式避免漏写and导致的测试漏判:
- 优先使用普通for循环+内部断言的写法:在可变风格测试套件中直接写常规for循环,在循环内部写
must断言即可,每一次循环的断言都会自动注册到测试套件,不需要手动拼接逻辑操作符:for (i <- 1 to 10) { i must_== 2 } for (i <- 1 to 10) { i must_== i } - 手动注册
Result结果:如果一定要使用Result.foreach,可以调用register方法主动把返回的Result注册到测试套件,哪怕不是最后一行也会被校验:Result.foreach(1 to 10) { i => i must_== 2 }.register Result.foreach(1 to 10) { i => i must_== i }.register - 所有
Result都用逻辑操作符拼接:把所有需要生效的Result返回值用and/or拼接为单个Result,作为测试块的最后返回值,保证所有结果都被纳入校验。
内容的提问来源于stack exchange,提问作者danio
相关产品推荐
相关产品推荐

