除了一些随机值之外,我希望始终使用至少一组固定的特殊值来测试我的所有属性。我想在我的生成器规范中定义它,而不是在使用该生成器类型的每个测试中。例如,如果我正在生成 Ints,我希望我的生成器始终为每个测试用例生成至少 0、1 和 -1。这可能吗?
到目前为止,我想出的最好的方法是制作一个大小合适的生成器,其中最小的n 个大小对应于我的n 个特殊情况。这至少是有问题的,因为当最大测试数配置为低于最大尺寸参数时,不会测试所有可能的尺寸。
除了一些随机值之外,我希望始终使用至少一组固定的特殊值来测试我的所有属性。我想在我的生成器规范中定义它,而不是在使用该生成器类型的每个测试中。例如,如果我正在生成 Ints,我希望我的生成器始终为每个测试用例生成至少 0、1 和 -1。这可能吗?
到目前为止,我想出的最好的方法是制作一个大小合适的生成器,其中最小的n 个大小对应于我的n 个特殊情况。这至少是有问题的,因为当最大测试数配置为低于最大尺寸参数时,不会测试所有可能的尺寸。
首先,Scalacheck 中已经存在偏差,因此除了其他值之外,很可能会选择0、1、-1Int.MaxValue
和。所以,如果这是您的担心,请不要担心。同样,可能会生成空字符串。Int.MinValue
Int
但是,如果您想为其他事情重现此行为,请使用Gen.oneOf
or 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%。
我今天遇到了同样的问题并最终来到这里,所以我想我会添加我的解决方案,即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
创建Prop
s ,然后将它们与使用后续值生成器创建的道具组合以进行测试。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)
}
}
}