2

下面的简单代码片段包含一个while看起来好像是无限的 -loop:

  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$-loop 之后while,Scoverage(可能还有其他一些覆盖工具)会抱怨,并且只计算 75% 的分支覆盖率(因为while算作一个分支点,并且false之前从未采用过该分支return)。

左右移动// $COVERAGE-OFF$,例如在 -body 关闭之前}while无济于事。

我如何强制它忽略不可能的分支?

4

2 回答 2

2

只需将循环头包装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-loop 主体中的每个语句都被覆盖,但它忽略false-branch,并报告100%测试覆盖率,例如在以下简单测试之后:

  "Whatever" should "do something" in {
    MyObjectName.findDivisor(57) should be(3)
  }
于 2018-09-27T21:05:58.143 回答
2

我建议您不要使用编译器,而是以编译器可以理解的方式提供代码。编译器理解无限递归。

@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没有分支,所以你的覆盖工具应该很高兴,而且,作为奖励,你不再需要一个虚拟异常。

于 2018-09-28T03:59:16.590 回答