ScalaCheck有效/无效测试边界

ScalaCheck有效/无效测试边界,scala,scalatest,scalacheck,Scala,Scalatest,Scalacheck,我正在使用ScalaCheck在ScalaTest中进行一些基于属性的测试。假设我想测试一个函数,f(x:Double):Double,它只为x>=0.0定义,并且对于该域之外的参数返回NaN。理想情况下,我想做这样的事情: import org.scalatest.FunSpec 导入org.scalatest.prop.generator驱动属性检查 def(x:Double)=Math.sqrt(x)//实际函数并不重要。 等级FTest 扩展FunSpec 使用GeneratorDriv

我正在使用ScalaCheck在ScalaTest中进行一些基于属性的测试。假设我想测试一个函数,
f(x:Double):Double
,它只为
x>=0.0
定义,并且对于该域之外的参数返回
NaN
。理想情况下,我想做这样的事情:

import org.scalatest.FunSpec
导入org.scalatest.prop.generator驱动属性检查
def(x:Double)=Math.sqrt(x)//实际函数并不重要。
等级FTest
扩展FunSpec
使用GeneratorDrivenProperty检查{
描述(“f(x)”){
它(“必须接受每个参数值并正确处理它”){
forAll{x:Double=>
val r=f(x)
如果(x>=0.0)断言(!r.isNaN&&r==Math.sqrt(x))//太简单了,我知道。;-)
else断言(r.isNaN)
}
}
}
}
现在,这是相当优雅和有效的,但我关心的是边界检查,因为我怀疑——在一般情况下——ScalaCheck是否能够找到边界并测试函数是否正确响应边界两侧的值(在本例中为>=0.0)。当然,我可以在任何时候使用
(ScalaTest替换ScalaCheck的
==>
操作符)来分离这两个条件,但这会花费更多的精力,而且会浪费大量生成的值:

FTest2类
扩展FunSpec
使用GeneratorDrivenProperty检查{
描述(“f(x)”){
它(“必须接受每个有效参数值并正确处理它”){
forAll{x:Double=>
无论何时(x>=0.0){
val r=f(x)
断言(!r.isNaN&&r==Math.sqrt(x))
}
}
}
它(“必须报告无效参数值的正确错误值”){
forAll{x:Double=>
每当(x<0.0)断言(f(x).isNaN)
}
}
}
}
(我知道我也可以使用客户生成器来限制范围,以便在不需要时
,但我认为这不是重点。如果我错了,请随时纠正我。)

所以,我好奇的是:

  • 有没有一种方法可以提示ScalaCheck边界值是什么,并确保它选择该值及其两侧的值
  • 除了这一点,还有其他同样优雅的方法吗?但哪一种方法能更好地自动找到边界

  • 感谢您的帮助~

    ScalaCheck无法自动确定您的函数将哪些值视为有效值;您需要在属性中对这些信息进行编码(无论何时使用
    )或在生成器中进行编码。选择哪种方法是特定于上下文的

    保持属性“小”是可取的:集中的正交属性更容易读/写/维护,并且您可以随时在以后组合它们以构建更全面的属性。因此,我会将这两个属性(快乐和不快乐的情况)分开

    为了避免“浪费”生成的值,我将使用两个单独的生成器(一个用于非负双精度,另一个用于负双精度);使用该方法时,无需使用

    val genNonnegativeDouble: Gen[Double] = Gen.choose(0, Double.MaxValue)
    
    val genNegativeDouble: Gen[Double] = Gen.negNum[Double]
    
    您的属性将如下所示:

    final class FTest2
        extends FunSpec
        with GeneratorDrivenPropertyChecks {
    
      describe("f") {
        it("must accept every valid argument value and handle it correctly") {
          forAll(genNonnegativeDouble) { x =>
              val r = f(x)
              assert(!r.isNaN && r === Math.sqrt(x))
          }
        }
    
        it("must report the correct error value for invalid argument values") {
          forAll(negativeDouble) { x =>
            assert(f(x).isNaN)
          }
        }
      }
    
    }
    
    顺便说一下

    • 您可能应该返回除
      Double.NaN
      以外的内容来指示失败;在这里,
      选项[Double]
      是一个很好的选择,因为失败的原因只有一个
    • 您应该只检查双精度近似相等

    谢谢您的回复。我猜你没有告诉我任何我不知道的事情。我曾希望有一种简单、简洁的方法来同时验证函数对好输入和坏输入的响应,方法是通知ScalaCheck输入边界在哪里。至于
    Double.NaN
    ,这就是
    Math.sqrt
    在域外给定参数时返回的结果-我永远不会在我自己的代码中使用它。:-)由于其目的是关注边界条件,我也不太担心使用公差来验证
    posNum
    negNum
    仅拾取整数值。我认为在这种情况下,
    choose
    将是定制生成器的更好基础。@scalabling True。我会相应地修改我的答案。