除了一些随机值之外,我还希望我的所有属性都至少使用一组固定的特殊值进行测试。我想在我的生成器规范中定义它,而不是在使用该生成器类型的每个测试中。例如,如果我生成Ints,我希望我的生成器始终为每个测试用例生成至少0,1和-1。这可能吗?
到目前为止,我提出的最好的方法是制作一个大小的生成器,其中最小的 n 大小对应于我的 n 特殊情况。这是有问题的,至少因为当最大测试次数配置为低于最大尺寸参数时,不会测试所有可能的尺寸。
答案 0 :(得分:17)
首先,已经在Scalacheck中存在偏差,因此除了以外很可能会选择0,1,-1,Int.MaxValue
和Int.MinValue
其他Int
值。所以,如果那是您的担心,请不要担心。同样,可能会生成空字符串。
但是,如果您想要为其他内容重现此行为,请使用Gen.oneOf
或Gen.frequency
,也许与Gen.choose
结合使用。由于oneOf
和frequency
将Gen
作为参数,因此您可以将特殊情况与通用生成器结合使用。
例如:
val myArb: Arbitrary[Int] = Arbitrary(Gen.frequency(
1 -> -1,
1 -> 0,
1 -> 1,
3 -> Arbitrary.arbInt.arbitrary
))
你所要求的几乎是你所要求的,有50%几率任意一次(这与我所说的偏见有关),以及-1,0和1各有16.6%。
答案 1 :(得分:1)
我今天有同样的问题,并在这里结束,以为我要添加我的解决方案,即在使用Prop
之前先生成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
函数首先使用Prop
为每个必须测试的值创建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)
}
}
}