我希望能使我的ScalaCheck属性测试在specs2测试套件中是暂时确定性的,以便于调试。目前,每次重新运行测试套件时可能会生成不同的值,这使得调试非常困难,因为你无法确定观察到的行为变化是由你的代码更改引起的,还是只是由于生成了不同的数据。
我该如何做?是否有正式方法来设置ScalaCheck使用的随机种子?
我正在使用sbt
来运行测试套件。
附加问题: 是否有官方方法可以打印ScalaCheck使用的随机种子,以便您甚至可以重现非确定性的测试运行?
我希望能使我的ScalaCheck属性测试在specs2测试套件中是暂时确定性的,以便于调试。目前,每次重新运行测试套件时可能会生成不同的值,这使得调试非常困难,因为你无法确定观察到的行为变化是由你的代码更改引起的,还是只是由于生成了不同的数据。
我该如何做?是否有正式方法来设置ScalaCheck使用的随机种子?
我正在使用sbt
来运行测试套件。
附加问题: 是否有官方方法可以打印ScalaCheck使用的随机种子,以便您甚至可以重现非确定性的测试运行?
Test.Params
类来更改所使用的 java.util.Random
实例,并提供自己的实例使其始终返回相同的值集合:
def check(params: Test.Parameters, p: Prop): Test.Result
[更新]case class MyRandomGenerator() extends java.util.Random {
// implement a deterministic generator
}
"this is a specific property" ! prop { (a: Int, b: Int) =>
(a + b) must_== (b + a)
}.set(MyRandomGenerator(), minTestsOk -> 200, workers -> 3)
object StringSpecification extends Properties("String")
,如ScalaCheck用户指南所示:https://github.com/rickynils/scalacheck/wiki/User-Guide - ErictestLength(String x) {
assert(x.length > 10, "Length OK for '" + x + "'");
}
奖励问题: 是否有官方的方法可以打印出ScalaCheck使用的随机种子,以便您甚至可以复现非确定性测试运行?
从specs2-scalacheck
版本4.6.0
开始,这是默认行为:
给定测试文件HelloSpec
:
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
class HelloSpec extends Specification with ScalaCheck {
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
class HelloSpec extends Specification with ScalaCheck {
s2"""
a simple property $ex1
"""
def ex1 = prop((s: String) => s.reverse.reverse must_== "")
}
build.sbt
配置:
import Dependencies._
ThisBuild / scalaVersion := "2.13.0"
ThisBuild / version := "0.1.0-SNAPSHOT"
ThisBuild / organization := "com.example"
ThisBuild / organizationName := "example"
lazy val root = (project in file("."))
.settings(
name := "specs2-scalacheck",
libraryDependencies ++= Seq(
specs2Core,
specs2MatcherExtra,
specs2Scalacheck
).map(_ % "test")
)
project/Dependencies
:
import sbt._
object Dependencies {
lazy val specs2Core = "org.specs2" %% "specs2-core" % "4.6.0"
lazy val specs2MatcherExtra = "org.specs2" %% "specs2-matcher-extra" % specs2Core.revision
lazy val specs2Scalacheck = "org.specs2" %% "specs2-scalacheck" % specs2Core.revision
}
sbt
控制台运行测试时:sbt:specs2-scalacheck> testOnly example.HelloSpec
[info] HelloSpec
[error] x a simple property
[error] Falsified after 2 passed tests.
[error] > ARG_0: "\u0000"
[error] > ARG_0_ORIGINAL: "猹"
[error] The seed is X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=
[error]
[error] > '' != '' (HelloSpec.scala:11)
[info] Total for specification HelloSpec
要复制特定的运行(即使用相同的种子),您可以从输出中获取seed
,并使用命令行scalacheck.seed
传递它:
sbt:specs2-scalacheck>testOnly example.HelloSpec -- scalacheck.seed X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=
这将产生与之前相同的输出。
您还可以使用setSeed
以编程方式设置种子:
def ex1 = prop((s: String) => s.reverse.reverse must_== "").setSeed("X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=")
提供 Seed
的另一种方式是通过传递隐式的 Parameters
,其中设置了 seed
:
package example
import org.specs2.mutable.Specification
import org.specs2.ScalaCheck
import org.scalacheck.rng.Seed
import org.specs2.scalacheck.Parameters
class HelloSpec extends Specification with ScalaCheck {
s2"""
a simple property $ex1
"""
implicit val params = Parameters(minTestsOk = 1000, seed = Seed.fromBase64("X5CS2sVlnffezQs-bN84NFokhAfmWS4kAg8_gJ6VFIP=").toOption)
def ex1 = prop((s: String) => s.reverse.reverse must_== "")
}
对于 scalacheck-1.12
,这个配置起作用:
new Test.Parameters {
override val rng = new scala.util.Random(seed)
}
对于 scalacheck-1.13
,由于 rng 方法已被移除,它不再起作用。有什么想法吗?
ScalaCheck
随机生成的。 - Robin Green