Scalacheck - 向命令添加参数
Scalacheck - Add parameters to commands
在用于状态测试的 Scalacheck documentation 中,提到了 ATM 机作为用例。为了使其工作,命令需要参数,例如 PIN 或取款金额。在给定的示例中,class Counter
中的方法没有参数。
现在我的问题是如何在 scalachecks 状态测试中测试这样的方法:
class Counter {
private var n = 0
def inc(i: Int) = n += i
...
}
命令的 run
和 nextState
方法不提供参数。添加 Random.nextInt
是行不通的,因为在 run
和 nextState
中值会不同并且测试失败:
case object Inc extends UnitCommand {
def run(sut: Sut): Unit = sut.inc(Random.nextInt)
def nextState(state: State): State = state + Random.nextInt
...
}
有什么方法可以将参数传递给 Sut
?
正如您可能从 genCommand
中注意到的那样,ScalaCheck Commands
实际上在 genInitialState
生成的初始状态和 [=11= 生成的一系列命令之间执行类似于笛卡尔积的操作].因此,如果您的某些命令实际上需要一个参数,则需要将它们从对象转换为 classes 并为它们提供一个 Gen
。所以修改文档中的示例你需要这样的东西:
/** A generator that, given the current abstract state, should produce
* a suitable Command instance. */
def genCommand(state: State): Gen[Command] = {
val incGen = for (v <- arbitrary[Int]) yield Inc(v)
val decGen = for (v <- arbitrary[Int]) yield Dec(v)
Gen.oneOf(incGen, decGen, Gen.oneOf(Get, Reset))
}
// A UnitCommand is a command that doesn't produce a result
case class Inc(dif: Int) extends UnitCommand {
def run(sut: Sut): Unit = sut.inc(dif)
def nextState(state: State): State = state + dif
// This command has no preconditions
def preCondition(state: State): Boolean = true
// This command should always succeed (never throw an exception)
def postCondition(state: State, success: Boolean): Prop = success
}
case class Dec(dif: Int) extends UnitCommand {
def run(sut: Sut): Unit = sut.dec(dif)
def nextState(state: State): State = state - dif
def preCondition(state: State): Boolean = true
def postCondition(state: State, success: Boolean): Prop = success
}
请注意,如果您的参数只是常量而不是变量(如 PIN 码的情况),您应该在命令中对它们进行硬编码或制定整个规范 class 而不是对象并从外部传递这些参数。
在用于状态测试的 Scalacheck documentation 中,提到了 ATM 机作为用例。为了使其工作,命令需要参数,例如 PIN 或取款金额。在给定的示例中,class Counter
中的方法没有参数。
现在我的问题是如何在 scalachecks 状态测试中测试这样的方法:
class Counter {
private var n = 0
def inc(i: Int) = n += i
...
}
命令的 run
和 nextState
方法不提供参数。添加 Random.nextInt
是行不通的,因为在 run
和 nextState
中值会不同并且测试失败:
case object Inc extends UnitCommand {
def run(sut: Sut): Unit = sut.inc(Random.nextInt)
def nextState(state: State): State = state + Random.nextInt
...
}
有什么方法可以将参数传递给 Sut
?
正如您可能从 genCommand
中注意到的那样,ScalaCheck Commands
实际上在 genInitialState
生成的初始状态和 [=11= 生成的一系列命令之间执行类似于笛卡尔积的操作].因此,如果您的某些命令实际上需要一个参数,则需要将它们从对象转换为 classes 并为它们提供一个 Gen
。所以修改文档中的示例你需要这样的东西:
/** A generator that, given the current abstract state, should produce
* a suitable Command instance. */
def genCommand(state: State): Gen[Command] = {
val incGen = for (v <- arbitrary[Int]) yield Inc(v)
val decGen = for (v <- arbitrary[Int]) yield Dec(v)
Gen.oneOf(incGen, decGen, Gen.oneOf(Get, Reset))
}
// A UnitCommand is a command that doesn't produce a result
case class Inc(dif: Int) extends UnitCommand {
def run(sut: Sut): Unit = sut.inc(dif)
def nextState(state: State): State = state + dif
// This command has no preconditions
def preCondition(state: State): Boolean = true
// This command should always succeed (never throw an exception)
def postCondition(state: State, success: Boolean): Prop = success
}
case class Dec(dif: Int) extends UnitCommand {
def run(sut: Sut): Unit = sut.dec(dif)
def nextState(state: State): State = state - dif
def preCondition(state: State): Boolean = true
def postCondition(state: State, success: Boolean): Prop = success
}
请注意,如果您的参数只是常量而不是变量(如 PIN 码的情况),您应该在命令中对它们进行硬编码或制定整个规范 class 而不是对象并从外部传递这些参数。