我有一个案例类,我正在尝试通过 ScalaCheck 进行测试。案例类包含其他类。
以下是类(class):
case class Shop(name: String = "", colors: Seq[Color] = Nil)
case class Color(colorName: String = "", shades: Seq[Shade] = Nil)
case class Shade(shadeName: String, value: Int)
我为每个人都有发电机
implicit def shopGen: Gen[Shop] =
for {
name <- Gen.alphaStr.suchThat(_.length > 0)
colors <- Gen.listOf(colorsGen)
} yield Shop(name, colors)
implicit def colorsGen: Gen[Color] =
for {
colorName <- Gen.alphaStr.suchThat(_.length > 0)
shades <- Gen.listOf(shadesGen)
} yield Color(colorName, shades)
implicit def shadesGen: Gen[Shade] =
for {
shadeName <- Gen.alphaStr.suchThat(_.length > 0) //**Note this**
value <- Gen.choose(1, Int.MaxValue)
} yield Shade(shadeName, value)
当我编写测试并简单地执行以下操作时:
property("Shops must encode/decode to/from JSON") {
"test" mustBe "test
}
我收到错误,测试挂起并在 51 次尝试后停止。我得到的错误是在 1 次成功的属性评估后放弃。 51 个评估被丢弃。
如果我从 shadesGen
中删除 Gen.alphaStr.suchThat(_.length > 0)
并将其替换为 Gen.alphaStr
那么有用。
问题
- 为什么
Gen.alphaStr
对shadesGen
有效,但Gen.alphaStr.suchThat(_.length > 0)
却无效? - 此外,当我多次运行测试(使用
Gen.alphaStr
)时,有些会通过,有些则不会。这是为什么?
最佳答案
您可能会因为 listOf
的实现方式而看到此行为。它内部基于 buildableOf
,而 buildableOf
又基于 buildableOfN
,它具有以下注释:
... If the given generator fails generating a value, the complete container generator will also fail.
你的数据结构本质上是一个列表的列表,所以即使是一个糟糕的一代也会诅咒整个数据结构被丢弃。显然,大多数失败都发生在底层。这就是为什么删除 shadeName
过滤器会有所帮助。因此,为了使其工作,您应该生成更多有效的字符串。您可以将 Gen.alphaStr
更改为一些基于 nonEmptyListOf
的定制生成器,例如:
def nonemptyAlphaStr:Gen[String] = Gen.nonEmptyListOf(alphaChar).map(_.mkString)
解决此问题的另一种简单方法是使用 retryUntil
而不是 suchThat
,例如:
implicit def shadesGen: Gen[Shade] =
for {
//shadeName <- Gen.alphaStr.suchThat(_.length > 0) //**Note this**
shadeName <- Gen.alphaStr.retryUntil(_.length > 0)
value <- Gen.choose(1, Int.MaxValue)
} yield Shade(shadeName, value)
关于scala - 如何让 scalacheck 在带有 Seq 的类上工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53435893/