11

除了一些随机值之外,我希望始终使用至少一组固定的特殊值来测试我的所有属性。我想在我的生成器规范中定义它,而不是在使用该生成器类型的每个测试中。例如,如果我正在生成 Ints,我希望我的生成器始终为每个测试用例生成至少 0、1 和 -1。这可能吗?

到目前为止,我想出的最好的方法是制作一个大小合适的生成器,其中最小的n 个大小对应于我的n 个特殊情况。这至少是有问题的,因为当最大测试数配置为低于最大尺寸参数时,不会测试所有可能的尺寸。

4

2 回答 2

19

首先,Scalacheck 中已经存在偏差,因此除了其他值之外,很可能会选择0、1、-1Int.MaxValue和。所以,如果这是您的担心,请不要担心。同样,可能会生成空字符串。Int.MinValueInt

但是,如果您想为其他事情重现此行为,请使用Gen.oneOfor Gen.frequency,也许与Gen.choose. 由于oneOffrequency作为Gen参数,您可以将特殊情况与通用生成器结合起来。

例如:

val myArb: Arbitrary[Int] = Arbitrary(Gen.frequency(
    1 -> -1, 
    1 ->  0, 
    1 -> 1, 
    3 -> Arbitrary.arbInt.arbitrary
))

几乎可以满足您的要求,任意整数的可能性为 50%(这将伴随我所说的偏差),-1、0 和 1 的可能性为 16.6%。

于 2011-09-28T00:47:16.507 回答
1

我今天遇到了同样的问题并最终来到这里,所以我想我会添加我的解决方案,即Prop在使用 a 之前生成我的特殊情况Gen,如下所示:

import org.scalacheck.Gen.{alphaChar, const}
import org.scalacheck.Prop.{forAll, passed}
import org.scalacheck.{Gen, Prop}

// evaluate fn first with some initial values, then with some generated ones
def forAllAfter[A](init: A*)(subsequent: Gen[A])(fn: A => Prop): Prop =
  init.foldLeft(passed) { case (p, i) => p && forAll(const(i))(fn) } && forAll(subsequent)(fn) 

// example of usage
val prop = forAllAfter('a', 'b', 'c')(alphaChar) { c =>
  println(c) 
  passed
}

这里的函数首先为每个必须测试的值forAllAfter创建Props ,然后将它们与使用后续值生成器创建的道具组合以进行测试。Gen.const

如果您使用ScalaTest的是,那么您需要将Checkers特征混合到您的测试中以评估结果Prop,如下所示:

import org.scalatest.WordSpec
import org.scalatest.prop.Checkers
import org.scalacheck.Gen.{alphaChar, const}
import org.scalacheck.Prop.{forAll, passed}
import org.scalacheck.{Gen, Prop}

class TestExample extends WordSpec with Checkers {

  def forAllAfter[A](init: A*)(subsequent: Gen[A])(fn: A => Prop): Prop =
    init.foldLeft(passed) { case (p, i) => p && forAll(const(i))(fn) } && forAll(subsequent)(fn)

  val prop: Prop = forAllAfter('a', 'b', 'c')(alphaChar) { c =>
    println(c)
    passed
  }

  "Test example" should {
    "Work correctly" in {
      check(prop)
    }
  }
}
于 2018-11-29T23:31:04.750 回答