有&&短路:|在ScalaCheck中的表达式

时间:2017-03-11 04:57:56

标签: scala scalatest boolean-expression short-circuiting scalacheck

我正在尝试在Scala Test FlatSpec中创建一个基于属性的测试,该测试使用ScalaCheck :|运算符为结束布尔表达式的不同部分提供失败消息。

但是,我遇到了&&运算符不会短路的问题。在这种情况下,表达式的早期部分会检查表达式的下一部分是否可以运行,否则后面的部分会抛出异常。

以下是问题的示例。如果decodedNone,则表达式应该在&&上短路,以便decoded.get不会运行,因为它会引发异常。

val value: Array[Int] = Array.fill(2)(0)
val encoded = encode(value)
val decoded: Option[Array[Int]] = decode(value)

decoded.isDefined :| "decoded None" &&
    value.sameElements(decoded.get)

当我在不使用:|运算符的情况下编写布尔值来给出失败消息时,decoded.isDefined上的测试失败而没有抛出异常。

val value: Array[Int] = Array.fill(2)(0)
val encoded = encode(value)
val decoded: Option[Array[Int]] = decode(value)

decoded.isDefined &&
    value.sameElements(decoded.get)

但是,当我在:|中添加失败消息时,NoSuchElementException行上的value.sameElements(decoded.get)失败,并且decoded.isDefined没有显示失败消息它会评估为假。

我使用的导入和测试类声明如下:

import org.scalacheck.Prop._
import org.scalatest.prop.Checkers
import org.scalatest.{FlatSpec, Matchers}

class ByteRWTests extends FlatSpec with Matchers with Checkers {

我正在以下列方式撰写财产检查:

it should "be equal" in {
  check(
    forAll { (int: Int) =>
      int == int
    }
  )
}

有没有办法让&&使用:|来处理表达式,或者是否有针对此问题的解决方法?

1 个答案:

答案 0 :(得分:1)

为什么你会看到差异

问题在于,虽然布尔值的&&是短路的,但&&上的Prop方法不是,并且您是否使用标签确定隐含的位置从布尔值转换为Prop。例如:

import org.scalacheck.Prop, Prop._

val value: Array[Int] = Array.fill(2)(0)
val decoded: Option[Array[Int]] = None

val p1: Prop = decoded.isDefined && value.sameElements(decoded.get)
val p2: Prop = decoded.isDefined :| "decoded None" && value.sameElements(decoded.get)

这里p1定义了解这个:

Prop.propBoolean(decoded.isDefined && value.sameElements(decoded.get))

虽然p2给出了这个:

(Prop.propBoolean(decoded.isDefined) :| "decoded None").&&(
  Prop.propBoolean(value.sameElements(decoded.get))
)

(值得一提的是why I don't like fancy implicit-conversion-based DSLs的另一个例子。)

解决方法

不幸的是,&&上的Prop方法无法在此处执行您想要的操作,但您可以定义自己的连接版本:

def propAnd(p1: => Prop, p2: => Prop) = p1.flatMap { r =>
  if (r.success) Prop.secure(p2) else Prop(_ => r)
}

然后:

scala> propAnd(decoded.isDefined :| "decoded None" , value.sameElements(decoded.get))
res1: org.scalacheck.Prop = Prop

scala> .check
! Falsified after 0 passed tests.
> Labels of failing property: 
decoded None

此方法实际存在于ScalaCheck中,但它是not part of the public API。对实现的评论确实注意到它“(可能应该在Prop模块中)”,所以如果你发现你做了很多这样的事情,你可能会尝试打开一个pull请求来从{{1转到Commands并公开。

在你给出的具体案例中,我可能建议在Prop上使用exists之类的内容,而不是检查它是否已定义,然后使用Option