Как заставить scalacheck работать на классе с Seq? - PullRequest
0 голосов
/ 22 ноября 2018

У меня есть класс дел, который я пытаюсь проверить с помощью ScalaCheck.Класс case содержит другие классы.

Вот классы:

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.alphaStr работает на shadesGen, а Gen.alphaStr.suchThat(_.length > 0) - нет?
  2. Также, когда я запускаю тест несколько раз (с Gen.alphaStr), некоторые проходят, а некоторые нет.Почему это?

1 Ответ

0 голосов
/ 26 ноября 2018

Вы, вероятно, видите это поведение из-за способа реализации 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)
...