0

为了避免 X & Y 问题,有一点背景:

我正在尝试建立一个 Web 项目,我将在其中复制业务逻辑服务器和客户端,显然是 Javascript 中的客户端和 Scala 中的服务器。我计划在 Cucumber 中编写业务逻辑,这样我就可以确保测试和功能在两边都对齐。最后,我想尝试将 ScalaCheck 和 JSCheck 引入其中,生成输入数据而不是指定数据。

基本上,这些语句的工作方式如下:

给定语句选择添加生成器。当语句指定函数以按顺序作用于这些值。然后语句获取输入数据和最终结果数据并运行一个属性。

目标是使这类东西可组合,因此您可以指定多个生成器、一组要在每个生成器上运行的操作,然后是一组属性,每个属性都将在输入和结果上运行。

已经在 J​​avascript(技术上是 Coffeescript)中完成了这项工作,当然使用动态语言很容易做到。基本上我希望能够在我的 scala 步骤定义中做的是,请原谅任意测试数据:

class CucumberSteps extends ScalaDsl with EN
                    with ShouldMatchers with QuickCheckCucumberSteps {
  Given("""^an list of integer between 0 and 100$""") {
    addGenerator(Gen.containerOf[List, Int](Gen.choose(0,100)))
  }
  Given("""^an list of random string int 500 and 700$""") {
    addGenerator(Gen.containerOf[List, Int](Gen.choose(500,700)))
  }

  When("""^we concatenate the two lists$""") {
    addAction {(l1: List[Int], l2: List[Int]) => l1 ::: l2 }
  }

  Then("""^then the size of the result should equal the sum of the input sizes$""") {
    runProperty { (inputs: (List[Int], List[Int]), result: (List[Int])) =>
      inputs._1.size + inputs._2.size == result._1.size
    }
  }
}

所以我想做的关键是创建一个特征 QuickCheckCucumberSteps,它将作为 API,实现 addGenerator、addAction 和 runProperty。

到目前为止,这是我粗略的,以及我被卡住的地方:

trait QuickCheckCucumberSteps extends ShouldMatchers {

  private var generators = ArrayBuffer[Gen[Any]]()
  private var actions = ArrayBuffer[""AnyFunction""]()

  def addGenerator(newGen: Gen[Any]): Unit =
    generators += newGen

  def addAction(newFun: => ""AnyFunction""): Unit =
    actions += newFun

  def buildPartialProp = {
    val li = generators
    generators.length match {
      case 1 => forAll(li(0))_
      case 2 => forAll(li(0), li(1))_
      case 3 => forAll(li(0), li(1), li(2))_
      case 4 => forAll(li(0), li(1), li(2), li(3))_
      case _ => forAll(li(0), li(1), li(2), li(3), li(4))_
    }
  }

  def runProperty(propertyFunc: => Any): Prop = {
    val partial = buildPartialProp
    val property = partial {

      ??? // Need a function that takes x number of generator inputs,
          // applies each action in sequence
          // and then applies the `propertyFunc` to the
          // inputs and results.
    }

    val result = Test.check(new Test.Parameters.Default {},
                            property)

    result.status match {
      case Passed => println("passed all tests")
      case Failed(a, l) => fail(format(pretty(result), "", "", 75))
      case _ => println("other cases")
    }
  }
}

我的关键问题是,我想让注释块成为一个函数,它接受所有添加的操作,按顺序应用它们,然后运行并返回属性函数的结果。这是否可以用 Scala 的类型系统来表达,如果可以,我该如何开始?很高兴阅读并获得这个,但我至少需要一条前进的道路,因为我现在不知道如何表达它。如果我在这里想要做的不清楚,很高兴加入我的 Javascript 代码。

4

1 回答 1

0

如果我是你,我不会将 ScalaCheck 生成器代码放在你的 Cucumber Given/When/Then 语句中:)。ScalaCheck api 调用是“测试平台”的一部分——所以不在测试中。试试这个(未编译/测试):

class CucumberSteps extends ScalaDsl with EN with ShouldMatchers {
  forAll(Gen.containerOf[List, Int](Gen.choose(0,100)), 
         Gen.containerOf[List, Int](Gen.choose(500,700)))
        ((l1: List[Int], l2: List[Int]) => {
          var result: Int = 0
          Given(s"""^a list of integer between 0 and 100: $l1 $""") {   }
          Given(s"""^a list of integer between 0 and 100: $l2 $""") {   }
          When("""^we concatenate the two lists$""") { result = l1 ::: l2 }
          Then("""^the size of the result should equal the sum of the input sizes$""") {
            l1.size + l2.size == result.size }
         })
}
于 2013-11-25T05:37:11.597 回答