【问题标题】:How to get ScalaCheck's Arbitrary to always generate some special case values?如何让 ScalaCheck 的 Arbitrary 始终生成一些特殊情况值?
【发布时间】:2011-09-27 12:55:52
【问题描述】:

除了一些随机值之外,我希望始终使用至少一组固定的特殊值来测试我的所有属性。我想在我的生成器规范中定义它,而不是在使用该生成器类型的每个测试中。例如,如果我正在生成 Ints,我希望我的生成器始终为每个测试用例生成至少 0、1 和 -1。这可能吗?

到目前为止,我想出的最好的方法是制作一个大小合适的生成器,其中最小的 n 大小对应于我的 n 特殊情况。这至少是有问题的,因为当最大测试数配置为低于最大尺寸参数时,不会测试所有可能的尺寸。

【问题讨论】:

    标签: scala scalacheck


    【解决方案1】:

    首先,在 Scalacheck 中已经存在偏差,因此除了其他 Int 之外,很可能会选择 0、1、-1、Int.MaxValueInt.MinValue价值观。所以,如果这是您的担心,请不要担心。同样,很可能会生成空字符串。

    但是,如果您想为其他事情重现此行为,请使用Gen.oneOfGen.frequency,也许与Gen.choose 结合使用。由于oneOffrequencyGen 为参数,您可以将特殊情况与泛型生成器结合起来。

    例如:

    val myArb: Arbitrary[Int] = Arbitrary(Gen.frequency(
        1 -> -1, 
        1 ->  0, 
        1 -> 1, 
        3 -> Arbitrary.arbInt.arbitrary
    ))
    

    几乎可以满足您的要求,任意整数的可能性为 50%(这将伴随我所说的偏差),-1、0 和 1 的可能性为 16.6%。

    【讨论】:

    • 好吧,我想我很可能会接受。感谢您的详尽回答!顺便说一句,我实际上正在生成布尔表达式。
    【解决方案2】:

    我今天遇到了同样的问题,最后来到这里,所以我想添加我的解决方案,即在使用 Gen 之前生成我的特殊情况的 Props,如下所示:

    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 函数首先使用Gen.const 为每个必须测试的值创建Props,然后将它们与使用后续值生成器创建的道具组合以进行测试。

    如果您使用的是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)
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-02-17
      • 1970-01-01
      • 1970-01-01
      • 2016-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多