如何使scalacheck与Seq一起上课?

时间:2018-11-22 17:31:31

标签: scala scalacheck

我有一个案例类,我正在尝试通过ScalaCheck进行测试。案例类包含其他类。

以下是课程:

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次后,测试挂起并停止。我得到的错误是Gave up after 1 successful property evaluation. 51 evaluations were discarded.

如果我从Gen.alphaStr.suchThat(_.length > 0)中删除了shadesGen,而只是将其替换为Gen.alphaStr,那么它将起作用。

问题

  1. 为什么拥有Gen.alphaStrshadesGen有用,但是Gen.alphaStr.suchThat(_.length > 0)却不起作用?
  2. 此外,当我多次(使用Gen.alphaStr进行测试时,有些通过,有些则没有。为什么会这样?

1 个答案:

答案 0 :(得分:1)

由于实施listOf的方式,您可能会看到此行为。里面是基于buildableOf的,而buildableOfN是基于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) ,例如:


var input = jQuery('<div><input id="edit-annotation-input" ' +
          'style="z-index: 100; position: absolute; top:' + (this.textPosition.y - 9) + 'px; left:'+ (this.textPosition.x + 8) +'px; width: ' +  (610 - 7 - this.textPosition.x) + 'px; border: none; color: #0bac3a; outline: none; background-color: transparent !important; padding: 0px; font-family: arial; font-size: 12pt; " ' +
          'spellcheck="false" type="text" name="mytext[]" value="'+string+'"/></div>');
jQuery("div #pad").append(input);