2012-09-28 30 views
14

我想提出我的ScalaCheck性能测试中我specs2测试套件确定性,暂时缓解调试。现在,每次重新运行测试套件时都会生成不同的值,这会使调试变得令人沮丧,因为您不知道观察到的行为更改是由代码更改引起的,还是仅由生成的不同数据引起。制作ScalaCheck测试确定性

我怎样才能做到这一点?有没有官方的方式来设置ScalaCheck使用的随机种子?

我使用sbt运行测试套件。

奖金的问题:是否有打印出由ScalaCheck使用的随机种子进行正式的方式,这样就可以重现即使是非确定性的试运行?

+0

这个不断变化的数据来自哪里?一个数据库?服务器? –

+0

@BrianAgnew不,它是由'ScalaCheck'随机生成的。 –

回答

10

如果您使用纯ScalaCheck性能,你应该能够使用Test.Params类改变所使用的java.util.Random实例,并提供自己总是返回相同的一组值:

def check(params: Test.Parameters, p: Prop): Test.Result

[更新]

我刚刚出版了新specs2-1.12.2,快照,你可以使用下面的语法来指定您的随机数发生器:

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) 
+0

“使用纯ScalaCheck属性”是什么意思?你的意思是,在那里没有使用任何specs2的东西? –

+0

我的意思是使用ScalaCheck规范:对象StringSpecification扩展了属性(“String”),如ScalaCheck UserGuide所示:https://github.com/rickynils/scalacheck/wiki/User-Guide – Eric

1

作为一般规则,在不确定性的输入进行测试时,你应该尝试呼应或保存在某个地方的投入时,有一个故障。

如果数据是小的,可以将其包含在该被示出给用户的标签或错误消息;例如,在一个的xUnit式测试:(因为我是新来的Scala语法)

testLength(String x) { 
    assert(x.length > 10, "Length OK for '" + x + "'"); 
} 

如果数据是大的,例如自动生成的数据库,你可能要么将其存储在非非易失性位置(​​例如。/ tmp带有时间戳名称)或显示用于生成它的种子。

下一步很重要:采取价值,或种子,或什么的,并把它添加到您的确定性的回归测试,以便它能够从现在开始检查每次。

你说你想ScalaCheck确定性“暂时”重现此问题;我说你已经找到了一个非常适合成为单元测试的错误边缘案例(可能经过一些手工简化)。

0

对于scalacheck-1.12这种配置工作:

new Test.Parameters { 
    override val rng = new scala.util.Random(seed) 
} 

对于scalacheck-1.13因为RNG方法删除它不工作了。有什么想法吗?