Scala Check / Scala测试:撰写生成器

时间:2017-08-23 16:00:07

标签: scala scalatest scalacheck

有没有办法在scala test / scala check中组合生成器?

例如,这是一个我想写的示例测试用例:

"The classifier" when {
  "given a string containing a state" should {
    "classify it as a state" in {
      val states = Seq(
        "Alabama", "Alaska", "Arizona", "Arkansas", "California", "Colorado", "Connecticut", "Delaware",
        "Florida", "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", "Kansas", "Kentucky",
        "Louisiana", "Maine", "Maryland", "Massachusetts", "Michigan", "Minnesota", "Mississippi",
        "Missouri", "Montana", "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico",
        "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", "Oregon", "Pennsylvania",
        "Rhode Island", "South Carolina", "South Dakota", "Tennessee", "Texas", "Utah", "Vermont",
        "Virginia", "Washington", "West Virginia", "Wisconsin", "Wyoming"
      )

      val inputData = for {
        zip <- Gen.const("10001")
        name <- Gen.oneOf(
          Gen.oneOf(states) + "HARRINGTON, JOHN",
          "HARRINGTON, JOHN " + Gen.oneOf(states),
          "HARRINGTON, " + Gen.oneOf(states) + " MD,JOHN"
        )
      } yield (zip, name)

      forAll (inputData) { case (zip: String, name: String) =>
        Clasifier.classify(zip, name) shouldBe Classification.STATE
      }
    }
  }
}

请注意“{1}}生成器中的name生成器inputData val

我怎样才能达到这样的目标?

更新:我已经开始工作,但不确定我是否在这里做正确的事。

      val inputData = for {
        zip <- Gen.const("10001")
        name <- Gen.oneOf(
          s"${Gen.oneOf(states).sample.get} HARRINGTON, JOHN",
          s"HARRINGTON, JOHN ${Gen.oneOf(states).sample.get}",
          s"HARRINGTON, ${Gen.oneOf(states).sample.get} MD,JOHN"
        )
      } yield (zip, name)

失败(预期失败)消息对我正在做的事情不是很有帮助:

TestFailedException was thrown during property evaluation.
  Message: STATE was not equal to INDIVIDUAL
  Location: (Classifier$Test.scala:142)
  Occurred when passed generated values (
    arg0 = (,) // 12 shrinks
  )

PS:正如评论中所要求的那样,这就是我期望输入数据的样子:

"Alabama Harringgon, John",
"Harriongton, Alabama John",
"Harrington, John Alabama",
"Maryland Harrington, John",
"Harrington, Maryland John",
"Harrington, John Maryland",
etc.

1 个答案:

答案 0 :(得分:1)

如果您想组成生成器,您可以像这样将状态包括在for理解中:

val inputData = for {
    zip <- Gen.const("10001")
    state <- Gen.oneOf(states)
    name <- Gen.oneOf(
      state + "HARRINGTON, JOHN",
      "HARRINGTON, JOHN " + state,
      "HARRINGTON, " + state + " MD,JOHN"
    )
  } yield (zip, name)

如果示例的结果为None,那么按照更新示例中的方式执行sample.get将引发异常。

之所以收到无用的失败消息是因为收缩,scalacheck将尝试将值减小到失败的最小值,在这种情况下,当两个值都是空字符串时。在大多数情况下,我发现这不是您想要的行为,您可以通过包含如下隐式代码来阻止它缩小值:

implicit val noShrinkString: Shrink[String] = Shrink.shrinkAny
implicit def noShrinkList[A]: Shrink[List[A]] = Shrink.shrinkAny

第一行通过为字符串分配相同类型的Any(完全不收缩)的收缩实例来阻止字符串收缩,而第二行则阻止列表收缩。

答案有点晚了,我相信您现在已经解决了您的问题,但是希望这可以帮助其他类似情况的人