Scoverage:对 "formally infinite" `while(true)` 循环执行 100% 的分支覆盖
Scoverage: enforce 100% branch coverage on "formally infinite" `while(true)` loops
下面的简单代码片段包含一个 while
循环,看起来好像是无限的:
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
while (true) {
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
}
// $COVERAGE-OFF$
throw new Error("unreachable")
// $COVERAGE-ON$
}
基础数学保证此方法始终终止(即使找不到合适的除数,它也必须在 n
处停止)。
尽管 $COVERAGE-OFF$
紧接在 while
循环之后,Scoverage(可能还有其他一些覆盖工具)会报错,并且只计算 75% 的分支覆盖(因为 while
计数作为一个分支点,并且 false
分支在 return
).
之前从未被采用
四处移动 // $COVERAGE-OFF$
,例如在 while
-body 结束 }
之前也无济于事。
如何强制它忽略不可能的分支?
只需将 while(true) {
循环头包装成一对单独的 $COVERAGE-OFF$
-$COVERAGE-ON$
评论:
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
// $COVERAGE-OFF$
while (true) {
// $COVERAGE-ON$
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
// $COVERAGE-OFF$
}
throw new Error("unreachable")
// $COVERAGE-ON$
}
现在 Scoverage 确保 while
-循环主体中的每个语句都被覆盖,但它忽略 false
-分支,并报告 100%
测试覆盖率,例如经过以下简单测试:
"Whatever" should "do something" in {
MyObjectName.findDivisor(57) should be(3)
}
我建议,不要与编译器对抗,而是以编译器可以理解的方式提供代码。编译器理解无限递归。
@tailrec def forever(op: => Unit): Nothing = {
op
forever(op)
}
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
forever {
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
}
}
forever
没有分支,因此您的覆盖工具应该会很满意,而且,作为奖励,您不再需要虚拟异常。
下面的简单代码片段包含一个 while
循环,看起来好像是无限的:
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
while (true) {
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
}
// $COVERAGE-OFF$
throw new Error("unreachable")
// $COVERAGE-ON$
}
基础数学保证此方法始终终止(即使找不到合适的除数,它也必须在 n
处停止)。
尽管 $COVERAGE-OFF$
紧接在 while
循环之后,Scoverage(可能还有其他一些覆盖工具)会报错,并且只计算 75% 的分支覆盖(因为 while
计数作为一个分支点,并且 false
分支在 return
).
四处移动 // $COVERAGE-OFF$
,例如在 while
-body 结束 }
之前也无济于事。
如何强制它忽略不可能的分支?
只需将 while(true) {
循环头包装成一对单独的 $COVERAGE-OFF$
-$COVERAGE-ON$
评论:
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
// $COVERAGE-OFF$
while (true) {
// $COVERAGE-ON$
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
// $COVERAGE-OFF$
}
throw new Error("unreachable")
// $COVERAGE-ON$
}
现在 Scoverage 确保 while
-循环主体中的每个语句都被覆盖,但它忽略 false
-分支,并报告 100%
测试覆盖率,例如经过以下简单测试:
"Whatever" should "do something" in {
MyObjectName.findDivisor(57) should be(3)
}
我建议,不要与编译器对抗,而是以编译器可以理解的方式提供代码。编译器理解无限递归。
@tailrec def forever(op: => Unit): Nothing = {
op
forever(op)
}
def findDivisor(n: Int): Int = {
require(n >= 2)
var i = 2
forever {
if (n % i == 0) {
return i
} else {
// do-nothing branch
}
i += 1
}
}
forever
没有分支,因此您的覆盖工具应该会很满意,而且,作为奖励,您不再需要虚拟异常。